/*
Theme Name: Censored Gallery
Theme URI: https://censoredgallery.com
Author: ZenithAgency
Author URI: https://github.com/ZenithAgency
Description: Custom WordPress theme for Censored Gallery — the iOS app that censors nudity in photos, video and the live camera, entirely on the device. Classic PHP templates, no page builder, no third-party requests.
Version: 0.1.0
Requires at least: 6.0
Requires PHP: 8.0
License: UNLICENSED
Text Domain: censoredgallery
Tags: one-column, custom-menu, accessibility-ready
*/

/* ===================================================================
   Censored Gallery — single stylesheet.

   Everything lives here on purpose: CONVENTIONS.md calls for one
   stylesheet enqueued with a filemtime() version. A build step would
   have to earn its place first, and so far nothing needs one.

   Order: tokens -> reset -> base -> layout -> header -> content ->
   footer -> utilities -> WordPress core classes.
   =================================================================== */

/* -------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------
   Palette taken from the app's DPKit/Sources/DPUI/DPTheme.swift so the
   site and the App Store screenshots read as one product. #060610 is the
   app's screen background and is the page colour here.

   The app's nav-bar colour (#081E29) is deliberately NOT a token any
   more. Both the header and the footer used it as a solid band; once the
   header became transparent glass the footer was the only lighter block
   left on the page and read as bolted on. Both now sit on the page
   surface and are separated by a hairline instead.

   The text alphas deliberately do NOT match the app. DPTheme's
   textSecondary is white at 0.55 and textMuted at 0.30 — on the web
   0.30 lands near 2.4:1 and fails WCAG AA. A phone held at arm's length
   and a browser are not the same reading problem. Lightened to pass.
   ------------------------------------------------------------------- */

:root {
    /* Brand */
    --cg-accent:          #13FEF9;
    --cg-accent-active:   #5FFBF7;
    --cg-accent-dim:      rgba(19, 254, 249, 0.14);
    --cg-android:         #3DDC84;   /* Android's brand green; the Android badge only */

    /* Surfaces */
    --cg-bg:              #060610;
    --cg-card:            rgba(255, 255, 255, 0.06);
    --cg-card-hover:      rgba(255, 255, 255, 0.09);
    --cg-border:          rgba(255, 255, 255, 0.12);
    --cg-border-soft:     rgba(255, 255, 255, 0.08);

    /* Text */
    --cg-text:            #FFFFFF;
    --cg-text-secondary:  rgba(255, 255, 255, 0.72);
    --cg-text-muted:      rgba(255, 255, 255, 0.55);

    /* Status — from DPTheme, unchanged */
    --cg-danger:          #EF4444;
    --cg-success:         #22C55E;
    --cg-warning:         #F59E0B;

    /* Type. System stack only: a font CDN would put a third-party
       request on the privacy page itself (DONT-BREAK.md §2). The
       sibling DeniedPixels theme loads Google Fonts; this one must not
       copy that. */
    --cg-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, sans-serif;
    --cg-font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo,
                    Consolas, monospace;

    /* Rhythm */
    --cg-measure:         42rem;   /* readable line length for legal copy */
    --cg-wide:            72rem;   /* header, footer, landing sections   */
    --cg-gutter:          1.25rem;
    --cg-radius:          14px;    /* matches GlassCard in the app       */
    --cg-radius-sm:       8px;

    /* Store badges. Apple's artwork is 119.66407x40; the height is what
       that ratio gives at the chosen width, and the Android badge is
       built to the same box so the pair matches exactly. */
    --cg-badge-w:         158px;
    --cg-badge-h:         calc(158px * 40 / 119.66407);
}

@media (min-width: 48rem) {
    :root {
        --cg-gutter: 2rem;
    }
}

/* -------------------------------------------------------------------
   2. Reset
   ------------------------------------------------------------------- */

*,
*::before,
*::after {
    box-sizing: border-box;
}

body,
h1, h2, h3, h4, h5, h6,
p, figure, blockquote, dl, dd,
ul, ol {
    margin: 0;
}

ul[class],
ol[class] {
    padding: 0;
    list-style: none;
}

img,
picture,
video,
canvas,
svg {
    display: block;
    max-width: 100%;
    height: auto;
}

input,
button,
textarea,
select {
    font: inherit;
    color: inherit;
}

/* -------------------------------------------------------------------
   3. Base
   ------------------------------------------------------------------- */

html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
    html {
        scroll-behavior: auto;
    }

    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

body {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    background-color: var(--cg-bg);
    color: var(--cg-text);
    font-family: var(--cg-font);
    font-size: 1rem;
    line-height: 1.65;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

a {
    color: var(--cg-accent);
    text-decoration-color: rgba(19, 254, 249, 0.4);
    text-underline-offset: 0.2em;
}

a:hover,
a:focus {
    color: var(--cg-accent-active);
    text-decoration-color: currentColor;
}

/* One visible focus ring for everything. Never remove it — the site is
   read by a reviewer who may well be tabbing through it. */
:focus-visible {
    outline: 2px solid var(--cg-accent);
    outline-offset: 3px;
    border-radius: 2px;
}

h1, h2, h3, h4 {
    line-height: 1.2;
    font-weight: 700;
    letter-spacing: -0.02em;
    text-wrap: balance;
}

h1 { font-size: clamp(2rem, 6vw, 3rem); }
h2 { font-size: clamp(1.5rem, 4vw, 2rem); }
h3 { font-size: clamp(1.2rem, 3vw, 1.4rem); }
h4 { font-size: 1.1rem; }

strong { font-weight: 650; }

hr {
    border: 0;
    height: 1px;
    background: var(--cg-border-soft);
    margin: 2.5rem 0;
}

code,
pre {
    font-family: var(--cg-font-mono);
    font-size: 0.9em;
}

code {
    background: var(--cg-card);
    border: 1px solid var(--cg-border-soft);
    border-radius: 4px;
    padding: 0.1em 0.35em;
}

pre {
    background: var(--cg-card);
    border: 1px solid var(--cg-border-soft);
    border-radius: var(--cg-radius-sm);
    padding: 1rem;
    overflow-x: auto;
}

pre code {
    background: none;
    border: 0;
    padding: 0;
}

/* -------------------------------------------------------------------
   4. Layout
   ------------------------------------------------------------------- */

.cg-wrap {
    width: 100%;
    max-width: var(--cg-wide);
    margin-inline: auto;
    padding-inline: var(--cg-gutter);
}

.cg-main {
    flex: 1 0 auto;          /* keeps the footer down on short pages */
    padding-block: 3rem 4rem;
    /* Catches decorative overflow — the hero glow is far wider than its
       column — so it is cut at the viewport edge, off-screen, instead of
       adding a horizontal scrollbar. This element is the right place for
       it: it spans the full viewport width, so the cut is never visible,
       and it is a sibling of .cg-header rather than an ancestor, so the
       sticky header is untouched. clip, not hidden: hidden would make
       this a scroll container.

       clip on one axis leaves the other visible, which is what lets the
       page-level line field below reach up past the top of <main> and
       sit behind the header. */
    overflow-x: clip;
    position: relative;
}

.cg-skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 100;
    background: var(--cg-accent);
    color: #04121A;
    font-weight: 650;
    padding: 0.75rem 1.25rem;
    border-radius: 0 0 var(--cg-radius-sm) 0;
}

.cg-skip-link:focus {
    left: 0;
    color: #04121A;
}

/* -------------------------------------------------------------------
   5. Header
   ------------------------------------------------------------------- */

/* No solid bar. The app's nav-bar colour sits a shade lighter than the
   page, and as a band across the top it fenced the hero off. A translucent
   panel in the page's own colour effectively disappears at rest, and
   only asserts itself once content scrolls underneath — where the blur,
   not a background, is what keeps the nav legible.

   No border either: a hairline is the other half of what made it read
   as a separate bar. Browsers without backdrop-filter still get the
   0.68 background, which is opaque enough to read against. */
.cg-header {
    position: sticky;
    top: 0;
    z-index: 50;
    background: rgba(6, 6, 16, 0.68);
    -webkit-backdrop-filter: blur(18px) saturate(140%);
    backdrop-filter: blur(18px) saturate(140%);
}

/* Sticky on phones and tablets only. On a touch screen the nav and the
   store button are worth keeping in reach; on a desktop, where the whole
   page is a short scroll and the pointer is precise, a bar following you
   down just eats vertical space.

   62rem is the theme's existing desktop threshold — the width the hero
   goes two-column at — so there is one definition of "desktop" here
   rather than two that can drift apart. */
@media (min-width: 62rem) {
    .cg-header {
        position: static;
        /* No glass either. The panel exists so the nav stays legible when
           content scrolls underneath, and at this width nothing ever
           does. Keeping it here only served to mask the page-level line
           field, which cut it off in a hard line at the header's bottom
           edge instead of letting it run up behind the nav. */
        background: transparent;
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
    }
}

.cg-header__inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    /* One row at every width: wordmark, then the nav — and from 48rem
       the store button — pushed right by the brand's auto margin. On a
       phone it is just the wordmark and the nav, which fit down to
       320px. Wrapping stays on as the safety net. Tight column gap by
       default; roomier once there is width to spare. */
    gap: 0.7rem 0.75rem;
    /* Asymmetric on purpose: the page continues below the header, so an
       equal inset reads as pressed against the top edge. The extra above
       optically centres the row. Slimmer on a phone, where the bar is
       sticky and every pixel of height is taken from the page. */
    padding-block: 1.15rem 0.8rem;
}

@media (min-width: 48rem) {
    .cg-header__inner {
        gap: 0.75rem 1.5rem;
        padding-block: 1.5rem 0.85rem;
    }
}

.cg-header__brand {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    font-weight: 700;
    font-size: 1.05rem;
    letter-spacing: -0.02em;
    color: var(--cg-text);
    text-decoration: none;
    margin-right: auto;
}

.cg-header__brand:hover,
.cg-header__brand:focus {
    color: var(--cg-accent);
}

/* The wordmark is the one string on the site that must not read as body
   copy. There is no display face to reach for — a font CDN is ruled out
   by DONT-BREAK.md §2 and nothing is self-hosted yet — so the treatment
   is built from case, weight and tracking instead of a typeface. The
   cyan/pink split is the chromatic offset the brand art is drawn with,
   and now that the logo image is gone it is the only place that motif
   survives in the header.

   One phone size. It used to grow below 24rem, where the nav wrapping
   to its own line left the first row half empty; with the nav back on
   the row there is no spare width there any more. */
.cg-header__name {
    font-size: 0.75rem;
    font-weight: 800;
    line-height: 1.1;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    white-space: nowrap;
    /* Letter-spacing leaves a trailing gap after the last character,
       which knocks the wordmark off-centre. Pull it back — the value has
       to track letter-spacing, so it is restated at the breakpoint. */
    margin-right: -0.08em;
    color: var(--cg-text);
    text-shadow:
        -1.5px 0 rgba(19, 254, 249, 0.68),
         1.5px 0 rgba(246, 34, 84, 0.62);
    transition: text-shadow 0.15s ease;
}

@media (min-width: 48rem) {
    .cg-header__name {
        font-size: 0.95rem;
        letter-spacing: 0.16em;
        margin-right: -0.16em;
    }
}

/* The brand link turns cyan on hover, which would flatten the split and
   lose the effect. Hold the name white and widen the offset instead.
   The resting state already carries most of the split, so hover only
   has to go a little further to still register as a response. */
.cg-header__brand:hover .cg-header__name,
.cg-header__brand:focus-visible .cg-header__name {
    color: var(--cg-text);
    text-shadow:
        -2.5px 0 rgba(19, 254, 249, 0.85),
         2.5px 0 rgba(246, 34, 84, 0.8);
}

/* The nav stays on the header's one row on a phone rather than
   collapsing into a burger or dropping to a second line. Two links do
   not need a burger, which would also need JS to be usable when
   CONVENTIONS.md asks the site to work without it; and a second line
   left the bar 119px tall with the nav marooned bottom-left. It fits
   because the links are tracked tighter here and the store button is
   not shown on a phone. Revisit when the site has enough links to need
   a burger. */
.cg-nav ul {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 0.9rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

@media (min-width: 48rem) {
    .cg-nav ul {
        gap: 0.25rem 1.5rem;
    }
}

/* Uppercase and tracked, so the nav reads as a set of labels rather than
   a row of sentences, and picks up the wordmark's treatment without
   competing with it — smaller, lighter weight, no chromatic split. */
.cg-nav a {
    position: relative;
    display: inline-block;
    padding: 0.35rem 0;
    color: var(--cg-text);
    text-decoration: none;
    font-size: 0.7rem;
    font-weight: 650;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    transition: color 0.15s ease;
}

@media (min-width: 48rem) {
    .cg-nav a {
        font-size: 0.75rem;
        letter-spacing: 0.1em;
    }
}

/* A pseudo-element rather than text-decoration: it can be animated, and
   it sits clear of the descenders instead of cutting through them. */
.cg-nav a::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 2px;
    border-radius: 1px;
    background: var(--cg-accent);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 0.18s ease;
}

.cg-nav a:hover,
.cg-nav a:focus-visible {
    color: var(--cg-accent);
}

.cg-nav a:hover::after,
.cg-nav a:focus-visible::after {
    transform: scaleX(1);
}

/* Current page wears the underline permanently — same mechanism as the
   hover, so the two can never drift out of alignment. */
.cg-nav .current-menu-item > a::after,
.cg-nav .current_page_item > a::after {
    transform: scaleX(1);
}


/* -------------------------------------------------------------------
   6. Content
   ------------------------------------------------------------------- */

.cg-article__header {
    margin-bottom: 2rem;
}

.cg-article__title {
    margin-bottom: 0.5rem;
}

.cg-article__meta {
    color: var(--cg-text-muted);
    font-size: 0.9rem;
}

/* Long-form copy — the privacy policy and support page live in here,
   so it has to be comfortable at length, not just pretty at a glance. */
.cg-prose {
    max-width: var(--cg-measure);
    color: var(--cg-text-secondary);
}

.cg-prose > * + * {
    margin-top: 1.15rem;
}

.cg-prose h2,
.cg-prose h3,
.cg-prose h4 {
    color: var(--cg-text);
    margin-top: 2.5rem;
}

.cg-prose h2 + *,
.cg-prose h3 + *,
.cg-prose h4 + * {
    margin-top: 0.75rem;
}

/* Markers restored. The reset strips them from any list carrying a
   class, and WordPress emits <ul class="wp-block-list"> — so editor
   content came out as bare indented lines. Everything the theme builds
   itself uses its own list classes and is unaffected. */
.cg-prose ul {
    padding-left: 1.4rem;
    list-style: disc;
}

.cg-prose ol {
    padding-left: 1.4rem;
    list-style: decimal;
}

.cg-prose ul ul {
    list-style: circle;
}

.cg-prose li::marker {
    color: var(--cg-accent);
}

.cg-prose li + li {
    margin-top: 0.5rem;
}

.cg-prose blockquote {
    border-left: 2px solid var(--cg-accent);
    padding: 0.25rem 0 0.25rem 1.25rem;
    color: var(--cg-text);
}

.cg-prose table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.95rem;
}

.cg-prose th,
.cg-prose td {
    border: 1px solid var(--cg-border-soft);
    padding: 0.6rem 0.8rem;
    text-align: left;
    vertical-align: top;
}

.cg-prose th {
    background: var(--cg-card);
    color: var(--cg-text);
    font-weight: 650;
}

.cg-prose img {
    border-radius: var(--cg-radius-sm);
}

/* Post list — index.php / home.php until Phase 3 gives it a real one. */
/* Blog
   -------------------------------------------------------------------
   Listing and post styles. The card is a shared template part, so these
   rules cover the index and every archive at once. */

.cg-page-head {
    margin-bottom: 3rem;
}

.cg-page-head__title {
    margin-bottom: 0.6rem;
}

.cg-page-head__lede {
    color: var(--cg-text-secondary);
    max-width: var(--cg-measure);
}

.cg-posts {
    display: grid;
    gap: 1.25rem;
}

/* Two columns, with the newest post leading across both. Three posts in
   a single three-column row left the index as one thin strip with the
   rest of the viewport empty under it; a lead card gives the page a
   shape and holds up whether there are three posts or thirty. */
@media (min-width: 46rem) {
    .cg-posts {
        grid-template-columns: repeat(2, 1fr);
        gap: 1.75rem;
    }

    .cg-posts > :first-child {
        grid-column: 1 / -1;
    }

    .cg-posts > :first-child .cg-card__media img {
        aspect-ratio: 24 / 9;
    }

    .cg-posts > :first-child .cg-card__body {
        padding: 1.75rem 2rem 2rem;
    }

    .cg-posts > :first-child .cg-card__title {
        font-size: 1.7rem;
    }

    .cg-posts > :first-child .cg-card__excerpt {
        font-size: 1rem;
        max-width: 46rem;
    }
}

.cg-card {
    display: flex;
    flex-direction: column;
    background: var(--cg-card);
    border: 1px solid var(--cg-border-soft);
    border-radius: var(--cg-radius);
    overflow: hidden;
    transition: border-color 0.15s ease, background-color 0.15s ease;
}

.cg-card:hover {
    background: var(--cg-card-hover);
    border-color: rgba(19, 254, 249, 0.3);
}

.cg-card__media img {
    width: 100%;
    height: auto;
    aspect-ratio: 16 / 9;
    object-fit: cover;
}

.cg-card__body {
    padding: 1.35rem;
}

.cg-card__meta,
.cg-single__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 0.6rem;
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--cg-text-muted);
}

.cg-card__cat,
.cg-single__cat {
    color: var(--cg-accent);
    text-decoration: none;
    font-weight: 650;
}

.cg-card__title {
    font-size: 1.15rem;
    line-height: 1.3;
    margin-bottom: 0.5rem;
}

.cg-card__title a {
    color: var(--cg-text);
    text-decoration: none;
}

.cg-card:hover .cg-card__title a {
    color: var(--cg-accent);
}

.cg-card__excerpt {
    color: var(--cg-text-secondary);
    font-size: 0.9rem;
    line-height: 1.6;
}

/* 404
   -------------------------------------------------------------------
   Centred and given real vertical room. A 404 is one short message and
   one button, and left at the top of a wide page it reads as a page that
   failed to load rather than one that is telling you something. */

.cg-notfound {
    max-width: 34rem;
    margin-inline: auto;
    padding-block: clamp(3rem, 10vw, 7rem) clamp(4rem, 12vw, 9rem);
    text-align: center;
}

/* Large, quiet, and behind the message rather than competing with it —
   the number is decoration, the sentence is the content. */
.cg-notfound__code {
    font-size: clamp(4.5rem, 18vw, 8rem);
    font-weight: 800;
    line-height: 1;
    letter-spacing: -0.04em;
    color: transparent;
    -webkit-text-stroke: 1px rgba(19, 254, 249, 0.35);
    margin-bottom: 0.5rem;
}

.cg-notfound__title {
    font-size: clamp(1.9rem, 6vw, 2.6rem);
    margin-bottom: 0.9rem;
}

.cg-notfound__lede {
    color: var(--cg-text-secondary);
    text-wrap: balance;
}

.cg-notfound__actions {
    margin-top: 2rem;
}

/* Support page
   ------------------------------------------------------------------- */

.cg-support {
    display: grid;
    gap: 3rem;
    align-items: start;
}

@media (min-width: 58rem) {
    .cg-support {
        grid-template-columns: 1.15fr 1fr;
        gap: 4rem;
    }
}

.cg-support__heading {
    font-size: 1.15rem;
    margin-bottom: 1.25rem;
}

.cg-support__direct {
    margin-top: 1.5rem;
    font-size: 0.9rem;
    color: var(--cg-text-muted);
}

/* Form
   ------------------------------------------------------------------- */

.cg-form__row {
    display: grid;
    gap: 0.4rem;
    margin-bottom: 1.25rem;
}

.cg-form label {
    font-size: 0.8rem;
    font-weight: 650;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--cg-text-secondary);
}

.cg-form input[type="text"],
.cg-form input[type="email"],
.cg-form textarea {
    width: 100%;
    padding: 0.75rem 0.9rem;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid var(--cg-border);
    border-radius: var(--cg-radius-sm);
    color: var(--cg-text);
    font-size: 0.95rem;
    /* Inputs do not inherit the page font on their own. */
    font-family: inherit;
    transition: border-color 0.15s ease, background-color 0.15s ease;
}

.cg-form textarea {
    resize: vertical;
    min-height: 9rem;
}

.cg-form input:focus,
.cg-form textarea:focus {
    outline: none;
    border-color: var(--cg-accent);
    background: rgba(255, 255, 255, 0.06);
}

/* The focus ring is removed above, so it has to come back some other
   way — a colour change alone is not a visible focus indicator. */
.cg-form input:focus-visible,
.cg-form textarea:focus-visible {
    outline: 2px solid var(--cg-accent);
    outline-offset: 2px;
}

.cg-form__hint {
    font-size: 0.8rem;
    color: var(--cg-text-muted);
}

.cg-form__actions {
    margin-top: 1.75rem;
}

/* Honeypot. Off-screen rather than display:none — some bots skip fields
   that are not rendered at all, and this one is meant to be filled in. */
.cg-form__trap {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

.cg-note--ok,
.cg-note--bad {
    padding: 0.85rem 1.1rem;
    margin-bottom: 1.5rem;
    border-radius: var(--cg-radius-sm);
    border: 1px solid;
    font-size: 0.9rem;
}

.cg-note--ok {
    border-color: rgba(34, 197, 94, 0.4);
    background: rgba(34, 197, 94, 0.08);
    color: #86efac;
}

.cg-note--bad {
    border-color: rgba(239, 68, 68, 0.4);
    background: rgba(239, 68, 68, 0.08);
    color: #fca5a5;
}

/* Single post
   ------------------------------------------------------------------- */

.cg-single__head {
    max-width: var(--cg-measure);
    margin-bottom: 2.25rem;
}

.cg-single__title {
    font-size: clamp(1.9rem, 5vw, 2.75rem);
    margin-bottom: 1rem;
}

.cg-single__lede {
    font-size: 1.1rem;
    color: var(--cg-text-secondary);
}

.cg-single__media {
    margin: 0 0 2.25rem;
    max-width: var(--cg-measure);
}

.cg-single__media img {
    width: 100%;
    height: auto;
    border-radius: var(--cg-radius);
}

/* Previous / next
   ------------------------------------------------------------------- */

.cg-postnav {
    display: grid;
    gap: 1rem;
    max-width: var(--cg-measure);
    margin-top: 3.5rem;
    padding-top: 2rem;
    border-top: 1px solid var(--cg-border-soft);
}

@media (min-width: 40rem) {
    .cg-postnav {
        grid-template-columns: repeat(2, 1fr);
    }
}

.cg-postnav__link {
    display: block;
    padding: 1rem 1.15rem;
    border: 1px solid var(--cg-border-soft);
    border-radius: var(--cg-radius);
    text-decoration: none;
}

.cg-postnav__link:hover {
    border-color: rgba(19, 254, 249, 0.35);
    background: var(--cg-card);
}

/* Sits in the second column even when there is no previous post, so
   "Next" never slides left into the previous slot. */
.cg-postnav__link--next {
    grid-column: -2;
    text-align: right;
}

.cg-postnav__dir {
    display: block;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--cg-text-muted);
    margin-bottom: 0.3rem;
}

.cg-postnav__title {
    display: block;
    color: var(--cg-text);
    font-weight: 650;
    line-height: 1.35;
}

/* Pagination */
.cg-pagination {
    margin-top: 2.5rem;
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.cg-pagination .page-numbers {
    display: inline-block;
    padding: 0.4rem 0.75rem;
    border: 1px solid var(--cg-border-soft);
    border-radius: var(--cg-radius-sm);
    text-decoration: none;
    font-size: 0.9rem;
}

.cg-pagination .page-numbers.current {
    background: var(--cg-accent-dim);
    border-color: rgba(19, 254, 249, 0.35);
    color: var(--cg-text);
}

/* -------------------------------------------------------------------
   7. Buttons
   ------------------------------------------------------------------- */

.cg-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.7rem 1.3rem;
    border-radius: 999px;
    border: 1px solid transparent;
    background: var(--cg-accent);
    color: #04121A;
    font-weight: 650;
    text-decoration: none;
    cursor: pointer;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.cg-btn:hover,
.cg-btn:focus {
    background: var(--cg-accent-active);
    color: #04121A;
}

.cg-btn--ghost {
    background: transparent;
    border-color: var(--cg-border);
    color: var(--cg-text);
}

.cg-btn--ghost:hover,
.cg-btn--ghost:focus {
    background: var(--cg-card);
    border-color: var(--cg-accent);
    color: var(--cg-text);
}

/* Apple's official badge.
   -------------------------------------------------------------------
   Sized by width only, with height auto, so the artwork's proportions
   are never altered — Apple's guidelines forbid stretching, recolouring
   or rebuilding it. The minimum they specify is 40px tall; 158px wide on
   this 119.66x40 viewBox works out at ~53px, comfortably clear.

   inline-block on the link so the focus ring wraps the badge rather than
   a full-width line box. */
.cg-appstore {
    display: inline-block;
    width: var(--cg-badge-w);
    max-width: 100%;
    line-height: 0;
    border-radius: 8px;
    transition: opacity 0.15s ease;
}

.cg-appstore:hover,
.cg-appstore:focus-visible {
    opacity: 0.85;
}

.cg-appstore svg {
    width: 100%;
    height: auto;
    display: block;
}

/* The pair of badges — Apple's, then Android's.
   -------------------------------------------------------------------
   One row, wrapping to two on the narrowest phones: two badges plus
   the gap outgrow a 360px viewport's content column. Centred only
   inside the centred section CTAs; in the hero it sits flush with the
   left-aligned copy above it. */
.cg-badges {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
}

.cg-section__cta .cg-badges {
    justify-content: center;
}

/* The Android badge.
   -------------------------------------------------------------------
   Built to Apple's geometry so the two sit as a matched pair: the same
   width, the height Apple's artwork works out to at that width, a 1px
   border, a platform mark and two lines of text. Where Apple's is white
   on black this is Android green on black — the same thing in another
   colour, not a different thing.

   Markup and text rather than vendored artwork because there is no
   official artwork: the app is not on Google Play (see
   template-parts/android-cta.php). */
.cg-android {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    box-sizing: border-box;
    width: var(--cg-badge-w);
    max-width: 100%;
    height: var(--cg-badge-h);
    padding-inline: 0.6rem 0.5rem;
    border: 1px solid var(--cg-android);
    border-radius: 8px;
    background: #000;
    color: var(--cg-android);
    text-decoration: none;
    line-height: 1;
    white-space: nowrap;
    transition: opacity 0.15s ease;
}

/* Outranks the base a:hover / a:focus (0,1,1), which would otherwise
   turn the whole badge cyan on hover. */
.cg-android:hover,
.cg-android:focus {
    color: var(--cg-android);
}

.cg-android:hover,
.cg-android:focus-visible {
    opacity: 0.85;
}

/* The viewBox is cropped to the head (23x13.5), so width alone sizes
   it and the height follows; Apple's logo is ~22x26px at this badge
   size, and a wide, short head of similar area holds its own beside it. */
.cg-android__icon {
    flex: none;
    width: 2.1rem;
    height: auto;
    fill: currentColor;
}

.cg-android__text {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

/* Sized against Apple's: at this height their small line is ~11px and
   the wordmark ~22px, set medium-weight. */
.cg-android__small {
    font-size: 0.7rem;
    font-weight: 400;
    letter-spacing: 0.01em;
}

.cg-android__big {
    font-size: 1.45rem;
    font-weight: 600;
    letter-spacing: -0.02em;
}

.cg-hero__cta {
    margin-top: 2rem;
}

/* Centred, because both sections that use it are centred. */
.cg-section__cta {
    margin-top: 2.75rem;
    display: flex;
    justify-content: center;
}

/* Tablet and desktop only. Not shown on a phone, on the user's call
   (2026-09-17): the two store badges sit in the hero a thumb's reach
   below, and a worded pill did not fit the one-row bar while an icon
   was not wanted. The markup is still rendered — display:none keeps it
   out of the tab order and the accessibility tree — so the header
   variant's Android href swap keeps working where it is shown. */
.cg-header__actions {
    display: none;
    align-items: center;
    gap: 0.5rem;
    flex: none;
}

@media (min-width: 48rem) {
    .cg-header__actions {
        display: flex;
    }
}

/* Pill with a round arrow badge on the trailing edge. The padding is
   asymmetric on purpose — the badge is already a circle of its own, so
   equal padding either side leaves a visible gap of dead space after
   it. */
.cg-btn--app {
    padding-inline: 1rem 0.35rem;
    gap: 0.6rem;
}

.cg-btn__badge {
    display: grid;
    place-items: center;
    flex: none;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 50%;
    /* Inverted out of the pill: dark disc, accent arrow. */
    background: #04121A;
    color: var(--cg-accent);
    transition: transform 0.18s ease;
}

.cg-btn__badge svg {
    width: 0.9rem;
    height: 0.9rem;
}

.cg-btn--app:hover .cg-btn__badge,
.cg-btn--app:focus-visible .cg-btn__badge {
    transform: translateX(2px);
}

/* Compact pill for the header, where a full-size button would set the
   bar's height rather than sit inside it. */
.cg-btn--sm {
    padding: 0.4rem 0.75rem;
    font-size: 0.8rem;
    white-space: nowrap;
}

/* The header pill is only shown from 48rem (see .cg-header__actions),
   so there is one size of it, not a phone-trimmed one. The asymmetric
   inline padding is the same idea as .cg-btn--app's: the disc on the
   trailing edge is already round, so equal padding leaves dead space
   after it. */
.cg-btn--app.cg-btn--sm {
    padding-inline: 0.8rem 0.3rem;
    gap: 0.45rem;
}

.cg-btn--app.cg-btn--sm .cg-btn__badge {
    width: 1.5rem;
    height: 1.5rem;
}

.cg-btn--app.cg-btn--sm .cg-btn__badge svg {
    width: 0.8rem;
    height: 0.8rem;
}

@media (min-width: 48rem) {
    .cg-btn--sm {
        padding: 0.45rem 1rem;
    }
}

/* Stands in for the store button until there is a listing to link to.
   It keeps the button's footprint so the header does not reflow when the
   real link appears, but it is a span, so none of the hover states that
   imply "clickable" should fire. */
.cg-btn--pending,
.cg-btn--pending:hover,
.cg-btn--pending:focus {
    cursor: default;
    border-style: dashed;
    border-color: var(--cg-border);
    background: transparent;
    color: var(--cg-text-muted);
}

/* -------------------------------------------------------------------
   8. Footer
   ------------------------------------------------------------------- */

/* DeniedPixels banner
   -------------------------------------------------------------------
   The last thing on every page, so it has to hold its own against the
   footer below and whatever section it follows. It is lit from the left
   rather than evenly: an even wash on a wide panel reads as a slightly
   lighter rectangle, while a corner source reads as a light in the
   scene. The outer bloom does the same job the icon tiles do — it is
   what separates "a panel" from "a panel that glows". */

.cg-promo {
    position: relative;
    padding-block: clamp(3rem, 7vw, 5rem);
}

.cg-promo__inner {
    position: relative;
    display: grid;
    gap: 1.75rem;
    align-items: center;
    padding: clamp(2rem, 4.5vw, 3rem);
    border-radius: 22px;
    border: 1px solid rgba(19, 254, 249, 0.3);
    background:
        radial-gradient(80% 160% at 8% 0%, rgba(19, 254, 249, 0.16), transparent 62%),
        linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.02)),
        #0B0E18;
    box-shadow:
        0 0 60px rgba(19, 254, 249, 0.12),
        0 22px 50px rgba(0, 0, 0, 0.5);
}

/* A brighter run along the top edge, brightest where the glow enters.
   A flat border all the way round is what makes a panel look boxed. */
.cg-promo__inner::before {
    content: "";
    position: absolute;
    inset: 0 22px auto;
    height: 1px;
    pointer-events: none;
    background: linear-gradient(
        90deg,
        rgba(19, 254, 249, 0.7),
        rgba(19, 254, 249, 0.15) 45%,
        transparent 75%
    );
}

@media (min-width: 52rem) {
    .cg-promo__inner {
        grid-template-columns: 1fr auto;
        gap: 3rem;
    }
}

.cg-promo__eyebrow {
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--cg-accent);
    margin-bottom: 0.6rem;
}

.cg-promo__title {
    font-size: clamp(1.6rem, 4vw, 2.1rem);
    margin-bottom: 0.7rem;
}

.cg-promo__body {
    color: var(--cg-text-secondary);
    font-size: 0.95rem;
    max-width: 40rem;
}

/* Never stretched by the grid, and never wrapped mid-label. */
.cg-promo__cta {
    justify-self: start;
    white-space: nowrap;
}

/* No background band. The app's nav-bar colour was a leftover from when
   the header carried it too; once that went transparent the footer became
   the only lighter block on the page, which is what made it read as
   bolted on. It now shares the page surface, separated by a hairline and
   a faint bloom rather than a slab of colour. */
.cg-footer {
    flex: none;
    position: relative;
    border-top: 1px solid var(--cg-border-soft);
    padding-block: 4rem 2rem;
    font-size: 0.9rem;
    color: var(--cg-text-muted);
    background:
        radial-gradient(80% 120% at 50% 0%, rgba(19, 254, 249, 0.05), transparent 70%);
}

.cg-footer__top {
    display: grid;
    gap: 2.5rem;
    padding-bottom: 2.5rem;
}

/* The brand column takes the extra width; the link column only ever needs
   enough for a line of text. */
@media (min-width: 46rem) {
    .cg-footer__top {
        grid-template-columns: 1.7fr 1fr;
        gap: 3rem;
    }
}

.cg-footer__mark {
    display: inline-block;
    margin-bottom: 0.9rem;
    color: var(--cg-text);
    text-decoration: none;
    font-size: 0.85rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    /* Deliberately without the header wordmark's chromatic split. Two of
       them on one page competing is one too many; this is the quiet
       echo, not a second logo. */
}

.cg-footer__mark:hover,
.cg-footer__mark:focus-visible {
    color: var(--cg-accent);
}

.cg-footer__blurb {
    max-width: 26rem;
    color: var(--cg-text-secondary);
    line-height: 1.65;
}

.cg-footer__heading {
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--cg-text-muted);
    margin-bottom: 0.9rem;
}

/* Shared by the footer nav and the hand-built "Also from us" list, so
   both render identically whether they come from a menu or from markup. */
.cg-footer__col .cg-menu {
    display: grid;
    gap: 0.55rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.cg-footer__col .cg-menu a {
    color: var(--cg-text-secondary);
    text-decoration: none;
}

.cg-footer__col .cg-menu a:hover,
.cg-footer__col .cg-menu a:focus-visible {
    color: var(--cg-accent);
}

.cg-footer__base {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem 1.5rem;
    padding-top: 1.75rem;
    border-top: 1px solid var(--cg-border-soft);
    font-size: 0.85rem;
}

.cg-footer__base p {
    margin: 0;
}

.cg-footer__claim {
    color: var(--cg-text-secondary);
}

/* -------------------------------------------------------------------
   9. Landing page
   -------------------------------------------------------------------
   Sections sit inside the .cg-wrap that header.php opens, so a
   full-bleed colour band isn't available without breaking the wrap for
   every other template. Inset rounded bands instead — which suits the
   app's own glass-card look better than edge-to-edge stripes would.
   ------------------------------------------------------------------- */

/* Hero
   ------------------------------------------------------------------- */

.cg-hero-layout {
    display: grid;
    gap: 3rem;
    align-items: center;
    padding-block: 1rem 4rem;
}

@media (min-width: 62rem) {
    .cg-hero-layout {
        grid-template-columns: 1.05fr 0.95fr;
        gap: 4rem;
    }
}

.cg-hero {
    max-width: 40rem;
}

.cg-hero__title {
    font-size: clamp(2.25rem, 8vw, 3.75rem);
    margin-bottom: 1.25rem;
}

.cg-hero__lede {
    font-size: clamp(1.05rem, 2.5vw, 1.25rem);
    color: var(--cg-text-secondary);
}

/* Device shots
   -------------------------------------------------------------------
   Two phones overlapped and tilted. The negative margin creates the
   overlap; the tilt stops them reading as a flat pair. Widths are
   percentages of this container rather than of the viewport, so the
   arrangement holds its proportions at every size instead of needing a
   breakpoint per width.

   The container is capped so the rotated phone's corner stays inside
   .cg-wrap's gutter — a tilted box is wider than its layout box, and
   overflowing here would put a horizontal scrollbar on the page. */
.cg-hero__phones {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    max-width: 32rem;
    margin-inline: auto;
    width: 100%;
}

/* One bloom behind the pair, not a rim on each phone.
   An earlier version put a cyan drop-shadow on every image, which traced
   each silhouette and read as two separate halos with a seam where they
   overlapped. A single ellipse well wider than the group reads as one
   light source behind both.

   Wide and faint rather than tight and bright: the devices cover the
   middle, so a hot core is spent where nothing can see it, and the part
   that does the work is the long shallow falloff around the outside.
   .cg-main clips whatever runs past the viewport.

   z-index 0 keeps it under the phones, which carry z-index 1 and 2. It
   cannot use a negative z-index the way the old hero glow did — that
   would drop it behind the page background and make it invisible. */
.cg-hero__phones::before {
    content: "";
    position: absolute;
    z-index: 0;
    inset: -28% -42%;
    pointer-events: none;
    background:
        radial-gradient(
            52% 46% at 50% 50%,
            rgba(19, 254, 249, 0.27),
            rgba(19, 254, 249, 0.15) 44%,
            rgba(19, 254, 249, 0.05) 70%,
            transparent 88%
        );
}

/* 52%, not 58%. The back phone is tilted, and a rotated box is wider
   than its layout box — at the old size its corner swung past the
   container and the clip sheared the phone's right edge off. This
   leaves the rotated extent inside the box with a little slack. */
.cg-hero__phone {
    position: relative;
    width: 52%;
    height: auto;
    flex: none;
    /* Black, and kept: this one is not for the page — it falls across
       the phone underneath and separates the two where they overlap,
       which is the one place a dark shadow still reads on a dark page. */
    filter: drop-shadow(0 10px 22px rgba(0, 0, 0, 0.55));
}

.cg-hero__phone--front {
    z-index: 2;
    transform: rotate(-2deg);
}

.cg-hero__phone--back {
    z-index: 1;
    margin-left: -20%;
    transform: rotate(7deg) translateY(4%);
}


/* Sections
   ------------------------------------------------------------------- */

/* clamp rather than a breakpoint: the gap that separates this from the
   hero wants to grow with the viewport, and a step change mid-scroll is
   more noticeable than a smooth one. */
.cg-section {
    padding-block: clamp(5rem, 12vw, 8.5rem) 1rem;
}

.cg-section__title {
    margin-bottom: 0.75rem;
}

/* balance evens the lines out and, more usefully here, stops a stray
   word being left alone on a last line. A centred lede makes that kind
   of orphan very visible. */
.cg-section__lede {
    color: var(--cg-text-secondary);
    max-width: var(--cg-measure);
    margin-bottom: 3rem;
    text-wrap: balance;
}

/* Feature grid
   -------------------------------------------------------------------
   Columns rather than cards: the copy is the substance here, and boxing
   each item would add eleven borders that say nothing. The icon tile
   carries the accent instead, which keeps the row scannable without
   fencing the text in. */

.cg-features {
    display: grid;
    gap: 2.75rem 2.5rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* One column straight to three, with no two-column step. There are three
   features, so a 2-up breakpoint would leave a lone item stranded on a
   second row directly under a symmetric pair. */
@media (min-width: 48rem) {
    .cg-features {
        grid-template-columns: repeat(3, 1fr);
    }
}

/* Centred, so the three read as one symmetric row rather than three
   left-aligned blocks with ragged right edges. The measure is capped
   per column because centred text gets hard to track once the lines
   run long — both edges move, so the eye has no fixed return point. */
.cg-section--centred {
    text-align: center;
}

.cg-section--centred .cg-section__lede {
    margin-inline: auto;
}

.cg-section--centred .cg-feature {
    max-width: 22rem;
    margin-inline: auto;
}

.cg-section--centred .cg-feature__icon {
    margin-inline: auto;
}

.cg-feature__icon {
    display: grid;
    place-items: center;
    width: 3.5rem;
    height: 3.5rem;
    margin-bottom: 1.25rem;
    /* Radius tracks the tile — 12px on a 56px box reads square. */
    border-radius: 16px;
    background: var(--cg-accent-dim);
    border: 1px solid rgba(19, 254, 249, 0.28);
    /* The SVG inherits this through currentColor. */
    color: var(--cg-accent);
    /* Two layers so the tile reads as lit rather than outlined: a tight
       rim that hugs the corner radius, and a wider bloom that falls off
       into the page. box-shadow rather than a pseudo-element — it already
       follows the border-radius, and it needs no negative z-index, which
       is what made the hero glow fragile. */
    box-shadow:
        0 0 16px rgba(19, 254, 249, 0.30),
        0 0 44px rgba(19, 254, 249, 0.14);
}

.cg-feature__icon svg {
    width: 1.85rem;
    height: 1.85rem;
}

.cg-feature__title {
    font-size: 1.05rem;
    margin-bottom: 0.45rem;
    color: var(--cg-text);
}

/* Decorative line field
   -------------------------------------------------------------------
   Sits behind a section and bleeds past .cg-wrap on both sides; .cg-main
   already clips at the viewport edge, so it is cut off-screen rather
   than adding a scrollbar.

   The section needs its content lifted above the field. It deliberately
   does NOT use a negative z-index on the field: that drops it behind the
   page background and makes it invisible, which is the trap the hero
   glow hit. */

/* Wrapper that hosts the field. Both sections inside it are lifted
   above the lines; without that, a positioned z-index 0 field paints
   over non-positioned section content. */
.cg-lined {
    position: relative;
}

.cg-lined > .cg-section {
    position: relative;
    z-index: 1;
}

/* Scrim between the field and the copy, on the features section only.
   The mesh is densest there and the body text sits right on it. The
   style gallery below needs none — its tiles are opaque, and only the
   faint tail of the field reaches it.

   The section carries z-index 1, so this ::after at z-index 0 lands
   above the field but below the section's own children, which are
   lifted to 1 by the rule underneath. */
.cg-section--scrim > * {
    position: relative;
    z-index: 1;
}

.cg-section--scrim::after {
    content: "";
    position: absolute;
    z-index: 0;
    inset: 0;
    pointer-events: none;
    background: radial-gradient(
        58% 48% at 50% 50%,
        rgba(6, 6, 16, 0.85),
        rgba(6, 6, 16, 0.5) 55%,
        transparent 78%
    );
}

/* The field behind a page heading, on the inner templates. The front
   page wraps two whole sections in .cg-lined; here it only needs to sit
   behind the heading block at the top, so the box is given an explicit
   height instead of the front page's aspect-ratio trick. */
/* The page-level field, on every template but the front page.
   -------------------------------------------------------------------
   A direct child of <main>, so it spans the page rather than a block.
   The negative top takes it up behind the header — <main>'s overflow is
   clipped horizontally only, so vertical overflow survives — and the
   height carries it down past the first section.

   Everything else in <main> is lifted above it. Without that the field
   is a positioned element over static content and paints on top of the
   page instead of behind it.

   Opacity is deliberately NOT set here, so it inherits the same values
   as the front page's field — 0.16, and 0.2 from 62rem up. An earlier
   version overrode it to 0.38, which was right while the field was a
   short crop behind one heading and far too strong now that it spans the
   page.

   The partial gets fit => slice, so the box crops rather than squashing
   the curves flat. */
.cg-main > .cg-wrap {
    position: relative;
    z-index: 1;
}

.cg-main > .cg-lines {
    top: -9rem;
    bottom: auto;
    /* Same bleed as the front page's field. With fit => slice the scale
       is set by whichever axis has to stretch furthest to cover, and at
       these proportions that is always the width — so matching the front
       page's -14vw is what puts the curves at the same size. Pinning it
       to the viewport edges instead rendered the sheet at 1:1, about a
       quarter smaller than the front page's. */
    left: -14vw;
    right: -14vw;
    /* Tall enough for the crop to reach past the dense boundary into the
       open fan. At 46rem it stopped at about 60% of the sheet, so these
       pages showed only the tightly packed far edge — same colour and
       opacity as the front page, measurably, but a busier composition,
       which reads as a different treatment. */
    height: 62rem;
    aspect-ratio: auto;
}

.cg-lines {
    position: absolute;
    z-index: 0;
    /* Overshoots the section so the sheet's own top and bottom edges
       land outside it and the fade has room to work. */
    top: -4rem;
    bottom: -6rem;
    left: -14vw;
    right: -14vw;
    /* Anchored to the top and held at the source aspect by default.
       On a phone the section is several times taller than it is wide,
       and preserveAspectRatio="none" stretched the sheet over all of it
       — the curves became steep, dense diagonals running behind every
       line of copy. Keeping the artwork's own proportions means it reads
       as the same graphic at any width. */
    aspect-ratio: 1440 / 1200;
    opacity: 0.16;
    pointer-events: none;
    /* Brand cyan. This was a desaturated steel blue while the field was
       near full strength, because at that weight --cg-accent fought the
       icon tiles — the one thing in this section that should glow. At the
       opacity below it no longer competes, so it can carry the accent. If
       the field is ever turned back up, desaturate it again. */
    color: var(--cg-accent);
    /* Softens both ends so the sheet has no hard edge where the section
       stops. */
    -webkit-mask-image: linear-gradient(to bottom, #000, #000 84%, transparent);
    mask-image: linear-gradient(to bottom, #000, #000 84%, transparent);
}

/* Once the layout is three columns the section is wide and short
   enough for the sheet to fill it, which is the composition the artwork
   was drawn for. */
@media (min-width: 62rem) {
    .cg-lines {
        /* Spans both sections. The fade is pushed to the very bottom so
           the fan's near lines — the wide-spaced, strongly curved ones
           that make this read as a surface — survive all the way down
           rather than being erased inside the first section. */
        bottom: -6rem;
        aspect-ratio: auto;
        opacity: 0.2;
    }
}

.cg-lines svg {
    width: 100%;
    height: 100%;
    display: block;
    /* Flipped horizontally, so the family converges to the left and fans
       out to the lower right. Done here rather than in the geometry: the
       generator and the JS share one coordinate space, and mirroring the
       maths would mean changing both and keeping them in step. A single
       transform on the element flips whatever they draw.
       transform-origin is stated because the default differs between
       SVG elements and replaced content. */
    transform: scaleX(-1);
    transform-origin: center;
    /* preserveAspectRatio="none" stretches the sheet to whatever box it
       lands in. Fine — it is abstract, and it guarantees coverage at
       every viewport without a second set of paths. */
}

/* Motion lives in assets/js/line-field.js.
   -------------------------------------------------------------------
   There are no keyframes here on purpose. A wave is a change of shape,
   and CSS can animate transforms but cannot morph a path — sliding a
   fixed shape around was tried and read as sliding, not waving. The
   script redraws the surface instead, both families from one function,
   so the weave stays coherent while it moves.

   prefers-reduced-motion is handled in the script rather than by the
   global rule, because there is no CSS animation left for that rule to
   collapse. It simply leaves the static paths alone. */


/* FAQ
   -------------------------------------------------------------------
   Left-aligned inside a centred section, like the privacy points: these
   are sentences to read, and a centred answer of this length gives the
   eye no fixed edge to come back to. */

.cg-faq {
    max-width: 46rem;
    margin-inline: auto;
    text-align: left;
    border-top: 1px solid var(--cg-border-soft);
}

.cg-faq__item {
    border-bottom: 1px solid var(--cg-border-soft);
}

.cg-faq__q {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1.5rem;
    padding: 1.15rem 0.25rem;
    cursor: pointer;
    font-weight: 650;
    color: var(--cg-text);
    /* Safari shows a disclosure triangle on summary unless both of these
       are cleared; the chevron below replaces it. */
    list-style: none;
}

.cg-faq__q::-webkit-details-marker {
    display: none;
}

.cg-faq__item:hover .cg-faq__q,
.cg-faq__item[open] .cg-faq__q {
    color: var(--cg-accent);
}

.cg-faq__mark {
    flex: none;
    display: grid;
    place-items: center;
    width: 1.5rem;
    height: 1.5rem;
    color: var(--cg-text-muted);
    transition: transform 0.18s ease, color 0.18s ease;
}

.cg-faq__mark svg {
    width: 1.15rem;
    height: 1.15rem;
}

.cg-faq__item[open] .cg-faq__mark {
    transform: rotate(180deg);
    color: var(--cg-accent);
}

.cg-faq__link {
    padding: 0 3rem 1.35rem 0.25rem;
    margin: -0.5rem 0 0;
    font-size: 0.925rem;
}

.cg-faq__a {
    padding: 0 3rem 1.35rem 0.25rem;
    margin: 0;
    color: var(--cg-text-secondary);
    font-size: 0.925rem;
    line-height: 1.65;
}

/* Circuit board
   -------------------------------------------------------------------
   Traces feeding the privacy panel, which reads as the chip they lead
   to. Full bleed so they run off both screen edges; .cg-main already
   clips at the viewport, so this cannot add a page scrollbar. */

/* The board is anchored to the panel, not to the section. The section's
   padding is lopsided — a large clamp above against 1rem below — so
   spanning it put the board's centre about 60px above the chip it feeds.
   Wrapping the two together makes the alignment exact at any padding. */
.cg-board {
    position: relative;
}

.cg-circuit {
    position: absolute;
    z-index: 0;
    /* Equal overshoot top and bottom, so it stays centred on the panel. */
    top: -7rem;
    bottom: -7rem;
    left: 50%;
    width: 100vw;
    transform: translateX(-50%);
    pointer-events: none;
    color: var(--cg-accent);
    /* Same weight as the line field behind the features section, so the
       two backgrounds read as one system. They already shared the accent
       token — what made the board look like a different colour was being
       roughly three times brighter. The layers below are relative weights
       within this, not absolute values. */
    opacity: 0.16;
    /* Softens the very top and bottom so the board does not start and
       stop on a hard line where the section happens to end. */
    -webkit-mask-image: linear-gradient(to bottom, transparent, #000 18%, #000 82%, transparent);
    mask-image: linear-gradient(to bottom, transparent, #000 18%, #000 82%, transparent);
}

.cg-circuit svg {
    width: 100%;
    height: 100%;
    display: block;
}

@media (min-width: 62rem) {
    .cg-circuit {
        opacity: 0.2;
    }
}

.cg-circuit__base {
    opacity: 0.55;
}

.cg-circuit__vias {
    opacity: 0.75;
}

/* The travelling charge. The filter sits on the group, not on each of
   the sixteen paths — one filter region instead of sixteen. */
.cg-circuit__pulse {
    opacity: 1;
    filter: drop-shadow(0 0 6px rgba(19, 254, 249, 0.6));
}

/* The pulse layer is inert until assets/js/circuit.js drives it: that
   file owns the dash pattern, the motion and the reduced-motion opt-out.
   Without JS the board is the static traces and vias, which is a
   finished image on its own. */
.cg-circuit__pulse path {
    opacity: 0;
}



/* Privacy panel
   -------------------------------------------------------------------
   A surface of its own, unlike the feature columns. This is the claim
   the product is built on, and left as plain text in the same rhythm as
   everything else it reads as one more list. The panel and its glow are
   doing the job a pull-quote would. */

.cg-privacy {
    max-width: 58rem;
    margin-inline: auto;
    padding: clamp(2rem, 5vw, 3.25rem);
    border-radius: 20px;
    border: 1px solid rgba(19, 254, 249, 0.18);
    position: relative;
    z-index: 1;
    /* Opaque, unlike the other cards. The traces behind it run under the
       panel and are meant to disappear there — with a translucent
       surface they show through the chip and the illusion goes. The
       final layer is a shade lighter than the page so the package reads
       as a component sitting on the board. */
    background:
        radial-gradient(120% 90% at 50% 0%, rgba(19, 254, 249, 0.12), transparent 70%),
        linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.02)),
        #0B0E18;
    box-shadow:
        0 0 70px rgba(19, 254, 249, 0.10),
        0 24px 60px rgba(0, 0, 0, 0.55);
}

/* The section's own padding already separates it; the panel supplies the
   rest, so the lede does not need the 3rem the open sections use. */
.cg-privacy .cg-section__lede {
    margin-bottom: 2.25rem;
}

.cg-points {
    display: grid;
    gap: 1.75rem 2.5rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

@media (min-width: 40rem) {
    .cg-points {
        grid-template-columns: repeat(2, 1fr);
    }
}

/* Left-aligned inside a centred section: these are four sentences to
   read, not four labels to scan, and centred body copy at this length
   gives the eye no fixed edge to return to. */
.cg-point {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    text-align: left;
}

.cg-point__icon {
    flex: none;
    display: grid;
    place-items: center;
    width: 1.5rem;
    height: 1.5rem;
    margin-top: 0.15rem;
    color: var(--cg-accent);
}

.cg-point__icon svg {
    width: 1.15rem;
    height: 1.15rem;
    stroke-width: 2.2;
}

.cg-point__title {
    font-size: 1rem;
    margin-bottom: 0.3rem;
    color: var(--cg-text);
}

.cg-point__body {
    color: var(--cg-text-secondary);
    font-size: 0.875rem;
    line-height: 1.6;
}

/* Style gallery — a snapping slider
   -------------------------------------------------------------------
   Fixed 300px slides in a scroll-snap track, centre-aligned, so whatever
   is nearest the middle is the one being looked at.

   The inline padding is what lets the first and last slide reach the
   centre; without it they can only ever sit against an edge. max() keeps
   it from going negative on a viewport narrower than a slide.

   The dimming is applied only once JS has marked the track: without it
   nothing carries .is-active, and every slide would sit permanently at
   the inactive opacity. Progressive enhancement, not a hard dependency —
   the slider still scrolls and snaps with scripting off. */

/* ul.cg-styles, not .cg-styles: the reset's `ul[class] { padding: 0 }` is
   specificity (0,1,1) and beats a lone class (0,1,0), so the centring
   padding below was silently dropped and the first slide could never
   reach the middle. Matching the type raises this to (0,1,1) too, and it
   is later in the file. */
ul.cg-styles {
    display: flex;
    gap: 1rem;
    /* Full bleed. Inside .cg-wrap the track ended at the content edge, so
       the neighbouring slides were sliced off mid-tile. Breaking out to
       the viewport lets them run off the screen instead. .cg-main already
       clips at the viewport, so this cannot add a page scrollbar. */
    width: 100vw;
    margin-inline: calc(50% - 50vw);
    list-style: none;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    /* 50vw, not 50%. Percentage padding resolves against the containing
       block — still the 1088px content column — while the track itself is
       100vw wide. 50% therefore computed half the column, and every slide
       came to rest half the bleed offset left of centre. The track is the
       viewport's width, so vw is the honest unit here. */
    padding-inline: max(var(--cg-gutter), calc(50vw - 150px));
    scroll-padding-inline: max(var(--cg-gutter), calc(50vw - 150px));
    cursor: grab;
    /* The snap points are the affordance; a scrollbar under the tiles
       just adds a grey bar to a dark section. */
    scrollbar-width: none;
    -ms-overflow-style: none;
}

.cg-styles::-webkit-scrollbar {
    display: none;
}

.cg-style {
    flex: 0 0 300px;
    scroll-snap-align: center;
    background: var(--cg-card);
    border: 1px solid var(--cg-border-soft);
    border-radius: var(--cg-radius);
    overflow: hidden;
    transition: opacity 0.28s ease, transform 0.28s ease, border-color 0.28s ease;
}

/* Every slide stays fully opaque; the centred one is distinguished by
   size and edge alone. Scale is visual only — it does not change the
   layout box, so the snap positions stay put as slides grow and shrink. */
.cg-styles--enhanced .cg-style {
    transform: scale(0.88);
}

.cg-styles--enhanced .cg-style.is-active {
    transform: scale(1);
    border-color: rgba(19, 254, 249, 0.45);
    box-shadow: 0 0 30px rgba(19, 254, 249, 0.14);
}

/* While a drag is in progress. Snapping is switched off in script for
   the duration, or every scrollLeft assignment fights the drag. */
ul.cg-styles.is-dragging {
    cursor: grabbing;
    scroll-snap-type: none;
    scroll-behavior: auto;
    user-select: none;
}

ul.cg-styles.is-dragging .cg-style {
    /* Transitions during a drag make the slides lag the pointer. */
    transition: none;
}

.cg-style__img {
    -webkit-user-drag: none;
    user-select: none;
}

/* Dots
   -------------------------------------------------------------------
   Built in script, so they never appear without the behaviour behind
   them. Real <button>s — they are controls, and a div would need the
   keyboard and role work rebuilding by hand. */

.cg-dots {
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 1.75rem;
}

.cg-dot {
    width: 0.55rem;
    height: 0.55rem;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.22);
    cursor: pointer;
    transition: background-color 0.2s ease, transform 0.2s ease;
}

.cg-dot:hover {
    background: rgba(255, 255, 255, 0.4);
}

.cg-dot[aria-current="true"] {
    background: var(--cg-accent);
    transform: scale(1.25);
}

.cg-style__img {
    width: 100%;
    height: auto;
    aspect-ratio: 1;
    object-fit: cover;
    display: block;
}

.cg-style__name {
    display: block;
    padding: 0.7rem 0.75rem;
    font-size: 0.85rem;
    font-weight: 600;
    text-align: center;
    color: var(--cg-text-secondary);
}

.cg-styles--enhanced .cg-style.is-active .cg-style__name {
    color: var(--cg-text);
}

.cg-note {
    margin-top: 1.75rem;
    color: var(--cg-text-muted);
    font-size: 0.85rem;
}

.cg-feature__body {
    color: var(--cg-text-secondary);
    font-size: 0.875rem;
    line-height: 1.6;
}

/* -------------------------------------------------------------------
   10. WordPress core classes
   -------------------------------------------------------------------
   Required for the theme to render editor output correctly. Missing
   these is what makes a hand-rolled theme look broken the first time
   someone floats an image in a page.
   ------------------------------------------------------------------- */

.screen-reader-text {
    border: 0;
    clip-path: inset(50%);
    height: 1px;
    width: 1px;
    margin: -1px;
    overflow: hidden;
    padding: 0;
    position: absolute;
    white-space: nowrap;
}

.screen-reader-text:focus {
    clip-path: none;
    height: auto;
    width: auto;
    margin: 0;
    padding: 0.75rem 1.25rem;
    background: var(--cg-accent);
    color: #04121A;
    z-index: 100;
}

.alignleft {
    float: left;
    margin: 0.5rem 1.5rem 1rem 0;
}

.alignright {
    float: right;
    margin: 0.5rem 0 1rem 1.5rem;
}

.aligncenter {
    display: block;
    margin-inline: auto;
}

.alignwide,
.alignfull {
    max-width: none;
}

.wp-caption {
    max-width: 100%;
}

.wp-caption-text,
.wp-block-image figcaption {
    color: var(--cg-text-muted);
    font-size: 0.85rem;
    margin-top: 0.5rem;
}

.sticky,
.gallery-caption,
.bypostauthor {
    /* Present so WordPress theme checks pass; no styling needed yet. */
}
