/* GripLog — shared styles.
   Every value below is lifted from the app's Theme.swift so the site and the
   app are the same product, not two designs that happen to share a logo.

   The three pages Apple links to (privacy, terms, changelog) keep their own
   inline styles on purpose: they are referenced from inside the app and from
   App Review, so they stay untouched. Everything new uses this file. */

:root {
    /* Backgrounds — AppTheme.bgDeep / bgConcrete / bgCard / bgElevated / bgInput */
    --bg-deep: #0a0a0c;
    --bg-concrete: #111114;
    --bg-card: #17181b;
    --bg-elevated: #202127;

    /* Text — AppTheme.textPrimary / textSecondary / textMuted */
    --text: #ededf0;
    --text-secondary: #8e8e96;
    --text-muted: #5c5c64;

    /* Accents */
    --ember: #e85d04;
    --ember-dim: #b84a03;
    --brass: #d4a574;

    /* Element colours — the same three the app paints skill trees with */
    --planche: #3b82f6;
    --front-lever: #dc2f02;
    --back-lever: #059669;

    /* Borders — AppTheme.border / borderLight */
    --border: #26272c;
    --border-light: #303138;

    /* AppTheme.cornerRadius / cornerRadiusSmall / cornerLarge */
    --radius: 18px;
    --radius-sm: 12px;
    --radius-lg: 22px;

    /* AppTheme.spacing family */
    --space-sm: 8px;
    --space: 16px;
    --space-lg: 24px;

    /* AppTheme.softShadow — diffuse, never a hard offset */
    --shadow: 0 6px 16px rgba(0, 0, 0, 0.40);
}

* { margin: 0; padding: 0; box-sizing: border-box; }

body {
    /* The ember bloom behind each device deliberately paints outside its box;
       clip only the horizontal axis so it can never produce a sideways scroll.
       `clip` rather than `hidden`: it does not turn body into a scroll port. */
    overflow-x: clip;
    font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Helvetica Neue', sans-serif;
    background-color: var(--bg-deep);
    color: var(--text);
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }

/* Data is monospaced in the app; it stays monospaced here. */
.mono { font-family: ui-monospace, 'SF Mono', SFMono-Regular, Menlo, monospace; }

/* ---------- Layout ---------- */

.wrap { max-width: 900px; margin: 0 auto; padding: 0 var(--space-lg); }
.narrow { max-width: 620px; }

/* One idea per screen: sections breathe rather than stack. The seam between
   two of them is the same wire the header draws — a hairline with a node on
   it, so the page reads as one strand from the tree down to the footer. */
section { position: relative; padding: 68px 0; }
section + section::before {
    content: "";
    position: absolute; top: 0; left: 0; right: 0; height: 1px;
    background: linear-gradient(90deg,
        transparent 0%, var(--border) 16%, var(--border) 84%, transparent 100%);
}
section + section::after {
    content: "";
    position: absolute; top: -3px; left: 50%; margin-left: -3px;
    width: 6px; height: 6px; border-radius: 2px;
    background: var(--ember-dim);
    box-shadow: 0 0 12px rgba(232, 93, 4, 0.45);
}

@media (max-width: 640px) { section { padding: 64px 0; } }

/* ---------- Type ---------- */

.eyebrow {
    display: flex; align-items: center; gap: 10px;
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 2px;
    text-transform: uppercase;
    color: var(--ember);
    margin-bottom: var(--space);
}

h1 {
    font-size: clamp(36px, 8vw, 54px);
    font-weight: 700;
    letter-spacing: 2px;          /* app tracks titles at 2, not 4 */
    text-transform: uppercase;
    line-height: 1.1;
}

h2 {
    font-size: clamp(23px, 4.5vw, 32px);
    font-weight: 600;
    letter-spacing: 0.5px;
    line-height: 1.25;
    margin-bottom: var(--space);
}

h3 { font-size: 18px; font-weight: 600; letter-spacing: 0.5px; margin-bottom: var(--space-sm); }

p { color: var(--text-secondary); font-size: 16px; }
p + p { margin-top: var(--space); }
.lead { font-size: 18px; line-height: 1.7; }

/* The app marks sections with a small label followed by a hairline
   (SectionHeader), not with a hard accent block. */
.rule {
    position: relative;
    height: 1px;
    background: linear-gradient(90deg, var(--ember-dim), var(--border) 42%, var(--border));
    margin: var(--space-lg) 0 var(--space-lg);
}
.rule::before {
    content: "";
    position: absolute;
    left: 0; top: -2.5px;
    width: 6px; height: 6px;
    border-radius: 2px;
    background: var(--ember);
}
.sr-only {
    position: absolute; width: 1px; height: 1px;
    margin: -1px; padding: 0; overflow: hidden;
    clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

.center { text-align: center; }
.center .eyebrow { justify-content: center; }
.idx {
    font-family: ui-monospace, 'SF Mono', SFMono-Regular, Menlo, monospace;
    color: var(--text-muted);
    letter-spacing: 1px;
}
.idx::after {
    content: ""; display: inline-block; vertical-align: middle;
    width: 20px; height: 1px; margin: 0 0 3px 10px;
    background: var(--border-light);
}
.center .rule {
    max-width: 120px; margin-left: auto; margin-right: auto;
    background: linear-gradient(90deg, var(--border), var(--ember-dim) 50%, var(--border));
}
.center .rule::before { left: 50%; margin-left: -3px; }

/* ---------- Hero ----------
   A slow ember aurora behind the name, so the banner reads as its own surface
   instead of running straight into the first section. The movement is real but
   unhurried — the app's identity is dark and data-forward, not a light show. */

.hero {
    position: relative;
    overflow: hidden;
    padding: 104px 0 80px;
    border-bottom: 1px solid var(--border);
    isolation: isolate;
    background: radial-gradient(120% 90% at 50% 0%, #17110d 0%, var(--bg-deep) 62%);
}

/* The moving gradient itself: one wide ember band drifting diagonally across
   the whole banner. Blurred hard, so it reads as light, not as a stripe. */
.hero::before {
    content: "";
    position: absolute;
    inset: -120px;
    z-index: -2;
    background: linear-gradient(115deg,
        #0a0a0c 0%, #100d0b 16%, #2b1405 31%,
        #7a3302 46%, #5e2802 54%,
        #2b1405 69%, #100d0b 84%, #0a0a0c 100%);
    background-size: 320% 320%;
    opacity: 0.42;
    filter: blur(70px);
    animation: hero-flow 15s ease-in-out infinite alternate;
    will-change: background-position;
}

@keyframes hero-flow {
    from { background-position: 0% 20%; }
    to   { background-position: 100% 80%; }
}

/* Three fields on different clocks: the movement never visibly loops, and the
   opacity breathing is what actually makes it read as alive. */
.hero-glow {
    position: absolute;
    z-index: -1;
    border-radius: 50%;
    pointer-events: none;
    will-change: transform, opacity;
    mix-blend-mode: screen;
}

.hero-glow.a {
    width: 900px; height: 620px;
    top: -140px; left: 50%; margin-left: -450px;
    background: radial-gradient(closest-side, rgba(232, 93, 4, 0.30), rgba(232, 93, 4, 0) 72%);
    filter: blur(40px);
    animation: aurora-a 13s ease-in-out infinite alternate;
}

.hero-glow.b {
    width: 640px; height: 460px;
    top: 90px; left: 50%; margin-left: -520px;
    background: radial-gradient(closest-side, rgba(212, 165, 116, 0.18), rgba(212, 165, 116, 0) 70%);
    filter: blur(50px);
    animation: aurora-b 17s ease-in-out infinite alternate;
}

.hero-glow.c {
    width: 560px; height: 380px;
    bottom: -90px; left: 50%; margin-left: 60px;
    background: radial-gradient(closest-side, rgba(184, 74, 3, 0.42), rgba(184, 74, 3, 0) 70%);
    filter: blur(45px);
    animation: aurora-c 15s ease-in-out infinite alternate;
}

/* An ember hairline closing the surface, sweeping slowly left to right —
   the same device the app uses to end a card. */
.hero-edge {
    position: absolute;
    left: -50%; right: -50%; bottom: -1px;
    height: 1px;
    background: linear-gradient(90deg,
        rgba(232, 93, 4, 0) 0%,
        rgba(232, 93, 4, 0.85) 50%,
        rgba(232, 93, 4, 0) 100%);
    animation: edge-sweep 14s ease-in-out infinite alternate;
}

@keyframes aurora-a {
    from { transform: translate3d(-260px, -50px, 0) scale(0.82); opacity: 0.45; }
    to   { transform: translate3d(260px,   60px, 0) scale(1.28); opacity: 1; }
}
@keyframes aurora-b {
    from { transform: translate3d(-60px, 70px, 0) scale(1.2);  opacity: 0.3; }
    to   { transform: translate3d(360px, -80px, 0) scale(0.82); opacity: 0.95; }
}
@keyframes aurora-c {
    from { transform: translate3d(140px, 60px, 0) scale(0.95); opacity: 0.35; }
    to   { transform: translate3d(-320px, -70px, 0) scale(1.35); opacity: 1; }
}
@keyframes edge-sweep {
    from { transform: translate3d(-18%, 0, 0); }
    to   { transform: translate3d(18%, 0, 0); }
}

/* Motion is decoration here; anyone who asked the system to calm down gets a
   still gradient instead. */
@media (prefers-reduced-motion: reduce) {
    .hero-glow, .hero-edge, .hero::before { animation: none; }
    .hero-glow.a { opacity: 0.9; }
}

@media (max-width: 640px) {
    .hero { padding: 76px 0 52px; }
    .hero-glow.a { width: 560px; height: 400px; margin-left: -280px; filter: blur(34px); }
    .hero-glow.b, .hero-glow.c { display: none; }
    .hero::before { filter: blur(50px); }
}

.hero .wrap { max-width: 1080px; }

.hero-grid {
    display: grid;
    grid-template-columns: minmax(0, 0.86fr) minmax(0, 1fr);
    gap: 56px;
    align-items: center;
}

.hero-copy .lead { margin-top: var(--space-lg); max-width: 420px; }
.hero .badge-row { justify-content: flex-start; margin-top: 36px; }

/* The wordmark, not type set in the UI face. The viewBox is cropped to the
   ink, so the width below is the width you actually see. */
.hero h1.logo { margin: 0; line-height: 0; }
.logo-mark {
    display: block;
    width: clamp(220px, 25vw, 316px);
    height: auto;
    color: var(--text);
}
@media (max-width: 860px) { .logo-mark { margin: 0 auto; } }


.badge-row {
    display: flex; align-items: center; justify-content: center;
    gap: 14px; margin-top: 40px; flex-wrap: wrap;
}
.app-icon { width: 44px; height: 44px; border-radius: var(--radius-sm); border: 1px solid var(--border); }
.badge-row img[alt^="Download"] { height: 44px; width: auto; object-fit: contain; }

/* ---------- Skill tree ----------
   The header is the product: nodes you cleared, a node you are on, and the
   ones still dark. It draws itself once on load, then keeps sending charge up
   the branches that are already earned. Same shapes and colours the app uses. */

.hero-tree { position: relative; }
.hero-tree svg { width: 100%; height: auto; overflow: visible; }

.tree-edges .e {
    fill: none;
    stroke-width: 1.5;
    stroke-linecap: round;
    stroke-dasharray: 1;
    stroke-dashoffset: 1;
    animation: tree-draw 0.9s cubic-bezier(0.33, 1, 0.68, 1) forwards;
    animation-delay: var(--d);
}
.tree-edges .cleared { stroke: var(--ember-dim); }
.tree-edges .locked  { stroke: var(--border-light); }

/* One short bright segment travelling the earned path, over and over. */
.charge {
    fill: none;
    stroke: var(--ember);
    stroke-width: 2;
    stroke-linecap: round;
    stroke-dasharray: 7 93;
    stroke-dashoffset: 100;
    opacity: 0;
    filter: drop-shadow(0 0 7px rgba(232, 93, 4, 0.75));
    animation: charge-run 4.2s linear 2s infinite;
}

.tree-nodes .n {
    transform-box: fill-box;
    transform-origin: center;
    transform: scale(0);
    animation: node-pop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
    animation-delay: var(--d);
}
.tree-nodes .cleared {
    fill: var(--ember);
    filter: drop-shadow(0 0 8px rgba(232, 93, 4, 0.45));
}
.tree-nodes .active {
    fill: var(--bg-deep);
    stroke: var(--ember);
    stroke-width: 2.5;
}
.tree-nodes .locked {
    fill: var(--bg-card);
    stroke: var(--border-light);
    stroke-width: 1.5;
}

/* The node you are working on breathes. */
.ring {
    fill: none;
    stroke: var(--ember);
    stroke-width: 1.5;
    transform-box: fill-box;
    transform-origin: center;
    opacity: 0;
    animation: ring-pulse 3s ease-out 1.6s infinite;
}

.tree-labels .lab {
    fill: var(--text-muted);
    font-family: inherit;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 1.6px;
    opacity: 0;
    animation: label-in 0.6s ease forwards;
    animation-delay: var(--d);
}
.tree-labels .on { fill: var(--brass); }

@keyframes tree-draw { to { stroke-dashoffset: 0; } }
@keyframes node-pop  { to { transform: scale(1); } }
@keyframes label-in  { to { opacity: 1; } }
@keyframes charge-run {
    0%       { stroke-dashoffset: 100; opacity: 0; }
    8%       { opacity: 1; }
    62%      { opacity: 1; }
    70%, 100% { stroke-dashoffset: 0; opacity: 0; }
}
@keyframes ring-pulse {
    0%   { transform: scale(0.55); opacity: 0; }
    25%  { opacity: 0.85; }
    100% { transform: scale(1.5); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
    .tree-edges .e { stroke-dashoffset: 0; animation: none; }
    .tree-nodes .n { transform: scale(1); animation: none; }
    .tree-labels .lab { opacity: 1; animation: none; }
    .charge, .ring { animation: none; opacity: 0; }
}

@media (max-width: 860px) {
    .hero-grid { grid-template-columns: 1fr; gap: 26px; text-align: center; }
    .hero-copy .eyebrow { justify-content: center; }
    .hero-copy .lead { margin-left: auto; margin-right: auto; }
    .hero .badge-row { justify-content: center; }
    .hero-tree { max-width: 400px; margin: 0 auto; }
    .tree-labels .lab { font-size: 14px; letter-spacing: 1.2px; }
}

/* On a phone the two columns cannot sit side by side, and stacking them turned
   the banner into four separate blocks in a row. The tree stops being the
   fourth block and becomes the surface the words sit on: same drawing, same
   animation, just behind instead of below. */
@media (max-width: 760px) {
    .hero { padding: 104px 0 92px; }
    .hero-grid { display: block; text-align: center; }

    .hero-tree {
        position: absolute;
        inset: 0;
        z-index: -1;
        display: grid;
        place-items: center;
        max-width: none;
        margin: 0;
        opacity: 0.26;
        pointer-events: none;
    }
    .hero-tree svg { width: 122%; }
    .tree-labels { display: none; }   /* unreadable at that scale anyway */

    .hero-copy .lead { max-width: 340px; }
    .hero .app-icon { display: none; } /* the badge already says which app */
    .hero .badge-row { margin-top: 30px; }
}

/* ---------- Showcase rows ---------- */

.split { display: grid; grid-template-columns: 1fr 1fr; gap: 60px; align-items: center; }
.split.reverse .split-media { order: -1; }

/* ---------- The device ----------
   A real object: brushed bezel, deep drop shadow, an ember bloom behind it and
   a few degrees of turn so the two columns are not both flat rectangles.
   Straightens out when you point at it. */

.phone {
    position: relative;
    isolation: isolate;
    max-width: 252px;
    margin: 0 auto;
    padding: 8px;
    border-radius: 40px;
    background: linear-gradient(155deg, #34353c 0%, #1a1b1f 40%, #0c0c0f 100%);
    border: 1px solid rgba(255, 255, 255, 0.07);
    /* The ember bloom is a shadow, not a pseudo-element: shadows never add to
       the scrollable area, so the glow cannot push the page sideways. */
    box-shadow:
        0 34px 70px rgba(0, 0, 0, 0.66),
        0 0 58px rgba(232, 93, 4, 0.17),
        0 0 120px rgba(232, 93, 4, 0.09),
        0 2px 0 rgba(255, 255, 255, 0.05) inset;
    transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}
.phone img { border-radius: 32px; }

.tilt-l { transform: perspective(1500px) rotateY(7deg) rotateX(2deg) rotate(-1deg); }
.tilt-r { transform: perspective(1500px) rotateY(-7deg) rotateX(2deg) rotate(1deg); }
.tilt-l:hover, .tilt-r:hover { transform: perspective(1500px) rotateY(0) rotateX(0) rotate(0); }

.phone-flat { max-width: 268px; margin-top: 48px; }

/* Two screens of the same idea: the trees you keep, and one of them opened. */
.phone-pair {
    position: relative;
    max-width: 376px;
    margin: 0 auto;
    padding-left: 96px;
}
.phone-pair .phone { max-width: 222px; }
.phone-pair .back {
    position: absolute;
    left: 0; top: 30px;
    z-index: 0;
    transform: perspective(1500px) rotateY(10deg) rotate(-2deg) scale(0.9);
    opacity: 0.92;
}
.phone-pair .front {
    position: relative;
    z-index: 1;
    margin: 0 0 0 auto;
    transform: perspective(1500px) rotateY(-6deg) rotate(1.5deg);
}
.phone-pair .back:hover, .phone-pair .front:hover {
    transform: perspective(1500px) rotateY(0) rotate(0) scale(1);
    z-index: 2;
}

/* Two screens side by side, leaning away from each other. */
.phone-duo {
    display: flex;
    justify-content: center;
    gap: 40px;
    margin-top: 52px;
}
.phone-duo .phone { max-width: 228px; margin: 0; }

/* ---------- Skills strip ----------
   Six named cards rather than six floating drawings: the names are what make
   it obvious this is a street-workout app and not a gym app. */

.wrap.wide { max-width: 1080px; }

.skills {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 12px;
}

/* The seventh tile is the argument: the list does not end. */
.skill-open {
    border-style: dashed !important;
    border-color: var(--border-light) !important;
    background: transparent !important;
}
.skill-open .inf {
    height: 62px;
    line-height: 62px;
    font-size: 44px;
    font-weight: 300;
    color: var(--ember);
}
.skill-open:hover { background: var(--bg-card) !important; }
.skills figure {
    text-align: center;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 18px 8px 14px;
    transition: transform 0.25s ease, background 0.25s ease, border-color 0.25s ease;
}
.skills img { width: 62px; height: 62px; margin: 0 auto; }
.skills figcaption {
    font-size: 10px; font-weight: 600; letter-spacing: 1px;
    text-transform: uppercase; color: var(--text-muted);
    margin-top: 12px;
}
.skills figure:hover {
    transform: translateY(-4px);
    background: var(--bg-elevated);
    border-color: var(--border-light);
}
.skills figure:hover figcaption { color: var(--text-secondary); }

/* ---------- Facts, four to a block ---------- */

.bento {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 14px;
    margin-top: 40px;
    text-align: left;
}
.bento-cell {
    position: relative;
    overflow: hidden;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 26px 26px 24px;
    transition: background 0.25s ease, border-color 0.25s ease;
}
/* the app's leading ember stripe, turned into a corner mark */
.bento-cell::after {
    content: "";
    position: absolute; top: 0; left: 0;
    width: 42px; height: 2px;
    background: var(--ember);
}
.bento-cell:hover { background: var(--bg-elevated); border-color: var(--border-light); }
.bento-cell h3 {
    font-size: 15px; font-weight: 600; letter-spacing: 0.3px;
    color: var(--text); margin-bottom: 6px;
}
.bento-cell p { font-size: 14px; margin: 0; }

/* ---------- Closing ----------
   No card. Every other section on this page sits straight on the background,
   and a boxed one at the end read as an advertisement pasted into a document.
   Instead the wire that separates the sections runs on into a filled node —
   the same shape the header uses for a skill you have cleared. */

.closer { padding: 0 0 104px; }

.closer-wire {
    position: relative;
    height: 96px;
    margin-bottom: 4px;
}
.closer-wire::before {
    content: "";
    position: absolute;
    left: 50%; top: 0;
    width: 1px; height: 66px;
    background: linear-gradient(180deg, var(--border) 0%, var(--ember-dim) 100%);
}
.closer-wire::after {
    content: "";
    position: absolute;
    left: 50%; top: 66px;
    margin-left: -7px;
    width: 14px; height: 14px;
    border-radius: 4px;
    background: var(--ember);
    box-shadow: 0 0 18px rgba(232, 93, 4, 0.5);
}

.closer .narrow { margin: 0 auto; }
.closer .badge-row { margin-top: 34px; }

/* ---------- Reveal on scroll ----------
   Guarded by .js so the page is fully readable if the script never runs. */

[data-reveal].rv {
    opacity: 0;
    transform: translateY(26px);
    transition:
        opacity 0.75s cubic-bezier(0.22, 1, 0.36, 1) var(--r, 0s),
        transform 0.75s cubic-bezier(0.22, 1, 0.36, 1) var(--r, 0s);
}
[data-reveal].in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
    [data-reveal].rv { opacity: 1; transform: none; transition: none; }
    .phone, .tilt-l, .tilt-r { transition: none; }
}

@media (max-width: 980px) { .skills { grid-template-columns: repeat(4, 1fr); } }

/* Seven tiles never divide evenly into two or three columns, and stacking them
   two-up made the icons enormous. On a phone the row carries itself past: the
   tiles are duplicated once and the track slides exactly half its width, so the
   loop closes with no visible seam and nothing to swipe. */
.skills-viewport { margin-top: 60px; }
.skills figure.dup { display: none; }

@media (max-width: 760px) {
    .skills-viewport {
        overflow: hidden;
        margin-left: calc(-1 * var(--space-lg));
        margin-right: calc(-1 * var(--space-lg));
        /* fade both ends so tiles enter and leave instead of being chopped */
        -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
        mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
    }
    .skills {
        display: flex;
        grid-template-columns: none;
        width: max-content;
        gap: 10px;
        margin-top: 0;
        animation: skills-marquee 34s linear infinite;
    }
    .skills figure.dup { display: block; }
    .skills figure {
        flex: 0 0 112px;
        padding: 14px 6px 12px;
    }
    .skills img { width: 46px; height: 46px; }
    .skills figcaption { font-size: 9px; letter-spacing: 0.8px; margin-top: 8px; }
    .skill-open .inf { height: 46px; line-height: 46px; font-size: 32px; }
}

/* Half the track is the seven originals; sliding by exactly that lands on the
   duplicate of the first tile, which looks identical to where it started. */
@keyframes skills-marquee {
    from { transform: translate3d(0, 0, 0); }
    to   { transform: translate3d(calc(-50% - 5px), 0, 0); }
}

@media (prefers-reduced-motion: reduce) {
    .skills { animation: none; }
    .skills-viewport { overflow-x: auto; }
}

@media (max-width: 760px) {
    /* In one narrow column, mixing left-aligned and centred sections reads as
       an accident. Everything centres, the way the hero already does. */
    .split { grid-template-columns: 1fr; gap: 36px; text-align: center; }
    .split .eyebrow { justify-content: center; }
    .split .rule { max-width: 120px; margin-left: auto; margin-right: auto;
        background: linear-gradient(90deg, var(--border), var(--ember-dim) 50%, var(--border)); }
    .split .rule::before { left: 50%; margin-left: -3px; }
    .split p { max-width: 460px; margin-left: auto; margin-right: auto; }
    /* The pair overlaps on every screen — that is its whole point — so it is
       written in percentages and simply scales down instead of collapsing. */
    .phone-pair {
        display: block;
        position: relative;
        max-width: 380px;
        margin: 0 auto;
        padding-left: 33%;
    }
    .phone-pair .phone { max-width: 100%; margin: 0; padding: 7px; border-radius: 34px; }
    .phone-pair .phone img { border-radius: 27px; }
    .phone-pair .back {
        position: absolute;
        left: 0; top: 26px;
        z-index: 0;
        width: 67%;
        opacity: 0.92;
        transform: perspective(1200px) rotateY(9deg) rotate(-2deg) scale(0.9);
    }
    .phone-pair .front {
        position: relative;
        z-index: 1;
        width: 100%;
        transform: perspective(1200px) rotateY(-6deg) rotate(1.5deg);
    }

    /* The duo is a different figure: two screens standing beside each other,
       leaning apart. It stays beside each other here too, just narrower. */
    .phone-duo { display: flex; gap: 12px; margin-top: 44px; }
    .phone-duo .phone {
        flex: 1 1 0; min-width: 0; max-width: none;
        margin: 0; padding: 6px; border-radius: 28px;
    }
    .phone-duo .phone img { border-radius: 22px; }
    .phone-duo .tilt-l { transform: perspective(1200px) rotateY(5deg) rotate(-1deg); }
    .phone-duo .tilt-r { transform: perspective(1200px) rotateY(-5deg) rotate(1deg); }
    .split.reverse .split-media { order: 0; }
    .tilt-l, .tilt-r { transform: none; }
    section { padding: 64px 0; }
}
@media (max-width: 640px) {
    .bento { grid-template-columns: 1fr; }
    .closer { padding-bottom: 76px; }
    .closer-wire { height: 76px; }
    .closer-wire::before { height: 52px; }
    .closer-wire::after { top: 52px; }
}

/* ---------- Cards ---------- */

.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--space); margin-top: 40px; }
.cards .soft-card { padding: 20px; }
.cards p { font-size: 14px; margin-top: 6px; }

/* ---------- Blog ---------- */

.post-list { display: flex; flex-direction: column; gap: 12px; margin-top: 40px; }
.post-item {
    display: block; text-decoration: none;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-left: 4px solid var(--ember);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 22px 24px;
    transition: background 0.15s;
}
.post-item:hover { background: var(--bg-elevated); }
.post-item .post-date {
    font-family: ui-monospace, 'SF Mono', SFMono-Regular, Menlo, monospace;
    font-size: 11px; letter-spacing: 1px; text-transform: uppercase;
    color: var(--text-muted);
}
.post-item h3 { color: var(--text); margin: 6px 0 4px; }
.post-item p { font-size: 14px; margin: 0; }

.post-empty {
    margin-top: 40px;
    padding: 40px 24px;
    border: 1px dashed var(--border-light);
    border-radius: var(--radius);
}
.post-empty p { margin: 0; font-size: 14px; color: var(--text-muted); }

article { padding: 72px 0 96px; }
article h2 { margin-top: 56px; }
article figure { margin: 40px 0; }
article figure img {
    border-radius: var(--radius);
    border: 1px solid var(--border);
    box-shadow: var(--shadow);
    margin: 0 auto;
}
article figcaption { font-size: 12px; color: var(--text-muted); text-align: center; margin-top: 12px; }
article .phone { max-width: 300px; }

.meta {
    font-family: ui-monospace, 'SF Mono', SFMono-Regular, Menlo, monospace;
    font-size: 11px; letter-spacing: 1px; text-transform: uppercase;
    color: var(--text-muted); margin-bottom: 20px;
}

/* Logged numbers pulled out of the prose, styled like the app's stat row. */
.stat-strip {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
    gap: 1px; background: var(--border);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    overflow: hidden;
    margin: 36px 0;
}
.stat { background: var(--bg-card); padding: 20px var(--space); text-align: center; }
.stat .value {
    font-family: ui-monospace, 'SF Mono', SFMono-Regular, Menlo, monospace;
    font-size: 24px; font-weight: 700; color: var(--text);
}
.stat .label {
    font-size: 10px; letter-spacing: 1px; text-transform: uppercase;
    color: var(--text-muted); margin-top: 6px;
}

/* ---------- Nav & footer ---------- */

/* The bar rides along with the page. Translucent over whatever scrolls under
   it, with the blur doing the work of a background; it only gains weight and a
   hairline once you have left the top of the page. */
nav {
    position: sticky;
    top: 0;
    z-index: 50;
    padding: 16px 0;
    background: rgba(10, 10, 12, 0.55);
    -webkit-backdrop-filter: blur(18px) saturate(150%);
    backdrop-filter: blur(18px) saturate(150%);
    border-bottom: 1px solid transparent;
    transition: background 0.3s ease, border-color 0.3s ease, padding 0.3s ease;
}
nav.scrolled {
    padding: 11px 0;
    background: rgba(10, 10, 12, 0.82);
    border-bottom-color: var(--border);
}
/* Browsers without backdrop-filter get an opaque bar instead of a milky one. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    nav { background: var(--bg-concrete); }
    nav.scrolled { background: var(--bg-concrete); }
}

nav .wrap { display: flex; align-items: center; justify-content: space-between; gap: var(--space); }

nav .brand { display: flex; align-items: center; line-height: 0; text-decoration: none; }
.brand-mark {
    width: 104px;
    height: auto;
    color: var(--text);
    transition: opacity 0.35s ease, transform 0.35s ease;
}
/* On the home page the hero already carries the logotype, so showing it twice
   in the same viewport reads as a mistake. It arrives when the hero leaves. */
.nav-hero .brand-mark { opacity: 0; transform: translateY(-8px); }
.nav-hero.scrolled .brand-mark { opacity: 1; transform: none; }

@media (max-width: 520px) { .brand-mark { width: 88px; } }
nav .nav-links { display: flex; gap: 20px; }
nav .nav-links a {
    font-size: 12px; letter-spacing: 0.5px;
    color: var(--text-muted); text-decoration: none; transition: color 0.2s;
}
nav .nav-links a:hover, nav .nav-links a[aria-current] { color: var(--ember); }

footer { border-top: 1px solid var(--border); padding: 40px 0 56px; text-align: center; }
.footer-links { display: flex; justify-content: center; flex-wrap: wrap; gap: var(--space-lg); margin-bottom: 14px; }
.footer-links a {
    font-size: 11px; color: var(--text-muted); text-decoration: none;
    letter-spacing: 0.5px; transition: color 0.2s;
}
.footer-links a:hover { color: var(--ember); }
.footer-email { color: var(--ember) !important; }
footer .copy { font-size: 11px; color: var(--text-muted); }

/* ============================================================
   Document pages — terms, privacy, changelog

   These three are linked from inside the app and read by App Review, so their
   markup and copy stay exactly as they were. Only the styling moved here, onto
   the same soft surfaces the app uses.
   ============================================================ */

.container { max-width: 720px; margin: 0 auto; padding: 56px var(--space-lg) 0; }

.back-link {
    display: inline-block;
    font-size: 12px;
    letter-spacing: 0.5px;
    color: var(--text-muted);
    text-decoration: none;
    margin-bottom: 32px;
    transition: color 0.2s;
}
.back-link:hover { color: var(--ember); }

.header-row {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--space); flex-wrap: wrap;
    padding-bottom: var(--space-lg);
    border-bottom: 1px solid var(--border);
    margin-bottom: 40px;
}
.header-content h1 {
    font-size: clamp(26px, 6vw, 36px);
    letter-spacing: 1px;
    text-transform: none;
    margin-bottom: 6px;
}
.header-content .subtitle { font-size: 12px; color: var(--text-muted); letter-spacing: 0.5px; }
.header-row .app-icon { width: 56px; height: 56px; border-radius: var(--radius-sm); border: 1px solid var(--border); }

/* Each clause is a soft card with the app's leading ember stripe. */
.section {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-left: 4px solid var(--ember);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 24px 26px;
    margin-bottom: var(--space);
}
.section h2 {
    font-size: 15px; font-weight: 600; letter-spacing: 1px;
    text-transform: uppercase; color: var(--text);
    margin-bottom: 12px;
}
.section p { font-size: 14px; }
.section ul { margin: 12px 0 0 18px; }
.section li { font-size: 14px; color: var(--text-secondary); margin-bottom: 6px; }
.section a { color: var(--ember); text-decoration: none; }
.section a:hover { text-decoration: underline; }

.highlight { color: var(--text); font-weight: 600; }

.effective-date {
    font-family: ui-monospace, 'SF Mono', SFMono-Regular, Menlo, monospace;
    font-size: 11px; letter-spacing: 1px; text-transform: uppercase;
    color: var(--text-muted); text-align: center; margin: 32px 0 8px;
}

/* Pricing block — terms */
.pricing-box {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 1px; background: var(--border);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    overflow: hidden; margin: 20px 0 16px;
}
.pricing-item { background: var(--bg-elevated); padding: 18px var(--space); text-align: center; }
.pricing-label {
    display: block; font-size: 10px; letter-spacing: 1px;
    text-transform: uppercase; color: var(--text-muted); margin-bottom: 6px;
}
.pricing-value {
    display: block;
    font-family: ui-monospace, 'SF Mono', SFMono-Regular, Menlo, monospace;
    font-size: 15px; font-weight: 700; color: var(--ember);
}

/* Language switcher — privacy */
.lang-switcher { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 32px; }
.lang-switcher a {
    font-size: 11px; letter-spacing: 0.5px; text-decoration: none;
    color: var(--text-muted);
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 7px 14px;
    transition: all 0.2s;
}
.lang-switcher a:hover { color: var(--text); border-color: var(--border-light); }
.lang-switcher a.active { color: #0a0a0c; background: var(--ember); border-color: var(--ember); }

/* Version accordion — changelog */
.accordion { display: flex; flex-direction: column; gap: 12px; }
.version-section {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-left: 4px solid var(--ember);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    overflow: hidden;
}
.version-section summary {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--space);
    padding: 18px 22px;
    cursor: pointer;
    list-style: none;
}
.version-section summary::-webkit-details-marker { display: none; }
.version-header { display: flex; align-items: center; gap: 12px; }
.version-number {
    font-family: ui-monospace, 'SF Mono', SFMono-Regular, Menlo, monospace;
    font-size: 15px; font-weight: 700; color: var(--text);
}
.summary-right { display: flex; align-items: center; gap: 14px; }
.version-date {
    font-size: 11px; letter-spacing: 0.5px; color: var(--text-muted);
}
.toggle-icon {
    font-size: 15px; color: var(--text-muted);
    transition: transform 0.2s;
    width: 16px; text-align: center;
}
.version-section[open] .toggle-icon { transform: rotate(45deg); }
.version-content { padding: 0 22px 20px; }
.version-content ul { margin-left: 18px; }
.version-content li { font-size: 14px; color: var(--text-secondary); margin-bottom: 8px; }
.version-content strong { color: var(--text); }

/* Shared footer inside document pages */
.footer-row { display: flex; align-items: center; justify-content: center; gap: 12px; margin-bottom: 18px; }
.footer-icon { width: 40px; height: 40px; border-radius: var(--radius-sm); border: 1px solid var(--border); }

@media (max-width: 640px) {
    .container { padding-top: 40px; }
    .section { padding: 20px; }
}
