/* One stylesheet, no build step. Seven static pages; a bundler would add a
   failure mode on release day and buy nothing.

   Light and warm. The product itself lives in a dark menu bar, so every
   screenshot on the page is dark — a pale page makes them read as objects
   sitting on paper rather than blending into the background. */

:root {
    --ink: #17161c;
    --ink-dim: #56525f;
    --ink-faint: #8b8794;
    --bg: #fbfaf8;
    --bg-raised: #ffffff;
    --bg-lift: #f4f2ef;
    --line: #e4e0db;
    --line-soft: #ecE8e3;
    --line-soft: #eceae5;
    --accent: #d19a2e;
    --accent-deep: #8a6209;
    --accent-2: #6155d4;
    --accent-ink: #2b1e08;
    --ok: #2e9c63;
    --shadow: 0 1px 2px rgba(23,22,28,.04), 0 8px 24px -12px rgba(23,22,28,.10);
    --shadow-lg: 0 2px 4px rgba(23,22,28,.04), 0 24px 60px -24px rgba(23,22,28,.22);
    --measure: 38rem;
    --page: 72rem;
    --radius: 16px;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
    margin: 0;
    /* `clip`, not `hidden`: hidden makes body a scroll container and kills the
       sticky header. This exists because the full-bleed theme gallery is
       100vw, and 100vw counts the vertical scrollbar's width — so without it
       every page grows a few stray pixels of horizontal scroll. */
    overflow-x: clip;
    background: var(--bg);
    color: var(--ink);
    font: 16px/1.65 ui-sans-serif, -apple-system, "SF Pro Text", system-ui, sans-serif;
    -webkit-font-smoothing: antialiased;
}

a { color: var(--accent-deep); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--ink); }

.wrap { max-width: var(--page); margin: 0 auto; padding: 0 1.75rem; }
.narrow { max-width: var(--measure); }

/* Atmosphere. In its own clipped, fixed layer: as bare pseudo-elements on
   body these overflowed the viewport and Safari grew a horizontal scrollbar
   — `overflow-x: hidden` on body does not clip position:fixed children. */
.bg-layer { position: fixed; inset: 0; overflow: hidden; pointer-events: none; z-index: 0; }
.bg-layer i {
    position: absolute; display: block; border-radius: 50%;
    filter: blur(80px); opacity: .30;
}
.bg-layer i:nth-child(1) {
    width: 46rem; height: 46rem; top: -22rem; left: -14rem;
    background: radial-gradient(circle, #d9d2ff, transparent 65%);
}
.bg-layer i:nth-child(2) {
    width: 40rem; height: 40rem; top: 6rem; right: -16rem;
    background: radial-gradient(circle, #ffe4b3, transparent 65%);
}
header.site, main, footer.site { position: relative; z-index: 1; }

/* ---------------------------------------------------------------- chrome -- */

header.site {
    position: sticky; top: 0; z-index: 20;
    background: rgba(251, 250, 248, .78);
    backdrop-filter: saturate(180%) blur(16px);
    border-bottom: 1px solid transparent;
    transition: border-color .25s ease, background .25s ease;
}
header.site.scrolled { border-bottom-color: var(--line); background: rgba(251, 250, 248, .94); }
header.site .wrap { display: flex; align-items: center; gap: 1.5rem; height: 62px; }
.brand {
    display: flex; align-items: center; gap: .6rem;
    font-weight: 640; color: var(--ink); text-decoration: none;
    letter-spacing: -.02em; font-size: 1.02rem;
}
.brand img { width: 28px; height: 28px; border-radius: 7px; }
header.site nav { margin-left: auto; display: flex; gap: 1.4rem; align-items: center; flex-wrap: wrap; }
header.site nav a { color: var(--ink-dim); text-decoration: none; font-size: .92rem; transition: color .15s ease; }
header.site nav a:hover { color: var(--ink); }

footer.site {
    border-top: 1px solid var(--line);
    margin-top: 7rem; padding: 3rem 0 4.5rem;
    color: var(--ink-faint); font-size: .88rem;
}
footer.site nav { display: flex; gap: 1.4rem; flex-wrap: wrap; margin-bottom: 1.25rem; }
footer.site a { color: var(--ink-dim); text-decoration: none; }
footer.site a:hover { color: var(--ink); }

/* ------------------------------------------------------------- typography - */

h1 {
    font-size: clamp(2.6rem, 8vw, 4.75rem);
    line-height: 1.03; letter-spacing: -.045em;
    margin: 0 0 1.25rem; font-weight: 680; color: var(--ink);
}
h2 {
    font-size: clamp(1.7rem, 3.6vw, 2.4rem);
    letter-spacing: -.035em; line-height: 1.14;
    margin: 0 0 1rem; font-weight: 660; color: var(--ink);
}
h3 { font-size: 1.08rem; margin: 0 0 .45rem; font-weight: 640; letter-spacing: -.015em; color: var(--ink); }
p { margin: 0 0 1.1rem; color: var(--ink-dim); }
p.lead { font-size: clamp(1.08rem, 2.1vw, 1.28rem); color: var(--ink-dim); max-width: var(--measure); line-height: 1.55; }
strong { color: var(--ink); font-weight: 620; }
small { color: var(--ink-faint); font-size: .85rem; }
ul { color: var(--ink-dim); padding-left: 1.15rem; }
li { margin-bottom: .5rem; }

section { padding: 5rem 0; }
section > h2 { max-width: var(--measure); }

.eyebrow {
    display: inline-flex; align-items: center; gap: .5rem;
    text-transform: uppercase; letter-spacing: .15em;
    font-size: .7rem; color: var(--ink-dim); font-weight: 640;
    margin: 0 0 1.4rem;
    border: 1px solid var(--line); border-radius: 999px;
    padding: .4rem .9rem; background: var(--bg-raised);
    box-shadow: var(--shadow);
}
.eyebrow::before {
    content: ""; width: 6px; height: 6px; border-radius: 50%;
    background: var(--ok);
}

/* ------------------------------------------------------------------ hero -- */

.hero { padding: 5.5rem 0 1rem; text-align: center; }
.hero .lead, .hero .eyebrow { margin-left: auto; margin-right: auto; }
.hero .lead { max-width: 34rem; }
.hero .btn-row { justify-content: center; }

/* ---------------------------------------------------------------- buttons - */

.btn {
    display: inline-flex; align-items: center; gap: .5rem;
    padding: .8rem 1.5rem; border-radius: 11px;
    font-weight: 620; font-size: .96rem; text-decoration: none;
    border: 1px solid var(--line); color: var(--ink);
    background: var(--bg-raised); box-shadow: var(--shadow);
    transition: transform .16s cubic-bezier(.22,.61,.36,1), box-shadow .16s ease, border-color .16s ease;
}
.btn:hover { color: var(--ink); border-color: #d5cfc7; transform: translateY(-2px); box-shadow: var(--shadow-lg); }
.btn-primary {
    background: linear-gradient(180deg, #efb959, #dd9f2c);
    color: var(--accent-ink); border-color: #cf9426;
    box-shadow: 0 1px 2px rgba(23,22,28,.06), 0 10px 24px -10px rgba(209,154,46,.55);
}
.btn-primary:hover {
    background: linear-gradient(180deg, #f3c26a, #e3a736);
    color: var(--accent-ink); border-color: #cf9426;
    box-shadow: 0 2px 4px rgba(23,22,28,.06), 0 16px 32px -10px rgba(209,154,46,.6);
}
.btn-row { display: flex; gap: .8rem; flex-wrap: wrap; align-items: center; margin: 2rem 0 1rem; }

/* ------------------------------------------------------------------ cards - */

.cards { display: grid; gap: 1.1rem; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); margin: 2.5rem 0 0; }
.card {
    border: 1px solid var(--line); border-radius: var(--radius);
    padding: 1.6rem 1.5rem; background: var(--bg-raised);
    box-shadow: var(--shadow);
    transition: transform .3s cubic-bezier(.22,.61,.36,1), box-shadow .3s ease;
    /* The two plans do not carry the same amount of copy, so without this the
       buy buttons sit at different heights and the pair reads as misaligned
       rather than as a choice between equals. */
    display: flex; flex-direction: column;
}
.card:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg); }
/* `.card-featured` was in the markup with no rule behind it, so the
   recommended plan was distinguished only by its tag. With three cards it has
   to win on sight. A tinted border and a stronger shadow do that without
   scaling it up, which would shift the grid and make the other two look
   broken. */
.card-featured { border-color: var(--accent); box-shadow: var(--shadow-lg); }
/* One rhythm at every join inside a card. It used to be .1rem between the
   description and its tick line and 2rem before the button, so the top of the
   card read as one clumped block with the button floating off below it. The
   button still pushes to the bottom to stay level across the three cards, but
   padding-top guarantees a gap even in the tallest one, where `auto` resolves
   to nothing. */
.card > *:last-child { margin-bottom: 0; }
.card h3 { margin-bottom: .55rem; }
.card p { margin: 0 0 .9rem; font-size: .94rem; }
.card .price { margin: 0 0 .95rem; }
.card .assured { margin: 0 0 .9rem; }
.card .btn-row { margin: 0 0 .8rem; margin-top: auto; padding-top: 1.15rem; }
/* Two lines in all three cards. The note is the last thing in the card and
   the button is pushed to the bottom above it, so a note that wraps to three
   lines in one card drops that card's button below its neighbours'. The
   min-height holds the floor if the copy is ever edited to one line. */
.card .checkout-note { margin: 0; min-height: calc(2 * .8rem * 1.45); }
.card .ico {
    display: grid; place-items: center;
    width: 38px; height: 38px; border-radius: 10px; margin-bottom: 1rem;
    background: #f1eefc; border: 1px solid #e2ddf7; font-size: 1.05rem;
}

.price { display: flex; align-items: baseline; gap: .45rem; margin: .4rem 0 .9rem; }
.price b { font-size: 2.4rem; font-weight: 680; letter-spacing: -.035em; color: var(--ink); }
.price span { color: var(--ink-faint); font-size: .9rem; }
/* Directly under the button, because that is where someone hesitates: the
   click leaves the site, and an unexpected third-party checkout is the moment
   a purchase gets abandoned. */
.checkout-note {
    margin: 0; font-size: .8rem; line-height: 1.45;
    color: var(--ink-faint);
}

.tag {
    display: inline-block; font-size: .66rem; letter-spacing: .12em;
    text-transform: uppercase; font-weight: 720;
    background: var(--accent); color: var(--accent-ink);
    padding: .2rem .5rem; border-radius: 5px; margin-left: .5rem; vertical-align: middle;
}

/* The guarantee used to live in the last row of a fully collapsed FAQ, three
   sections below the buttons it exists to de-risk. On a $15 impulse buy from
   a developer nobody has heard of, this line is doing more work than any
   feature on the page, so it sits where the decision is made. */
.refund-line {
    display: flex; align-items: center; gap: .5rem;
    margin: 1.4rem 0 0; font-size: .9rem; color: var(--ink-dim);
}
/* No max-width and no nowrap: the sentence is short enough to sit on one line
   at any width the cards themselves are readable at, and on a phone it should
   still be allowed to wrap rather than push the page sideways. */
.refund-line .tick { flex: none; color: var(--ok); }

/* The download CTA hands over a disk image and the page used to stop there.
   Where it goes, whether it clutters the Dock, and what it will ask for are
   the three things a first-timer hesitates over, answered before the click
   rather than after it. */
.steps {
    display: grid; gap: 1.1rem; margin: 2.5rem 0 0; padding: 0;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    counter-reset: step;
}
.steps li {
    list-style: none; border: 1px solid var(--line);
    border-radius: var(--radius); padding: 1.4rem 1.35rem;
    background: var(--bg-raised);
}
.steps .n {
    display: grid; place-items: center; width: 26px; height: 26px;
    border-radius: 50%; background: var(--accent); color: var(--accent-ink);
    font-size: .82rem; font-weight: 700; margin-bottom: .8rem;
}
.steps b { display: block; margin-bottom: .35rem; font-weight: 620; }
.steps p { margin: 0; font-size: .92rem; color: var(--ink-dim); }

.tag-quiet {
    background: transparent; color: var(--ink-faint);
    border: 1px solid var(--line);
}

/* Hover, for the things that did not have it. Pricing cards, bento tiles and
   the theme strips already lifted; the screenshots, the install steps, the
   battery figures and the FAQ rows did not, which made half the page feel
   alive and the other half inert.

   One language throughout: a small lift and a deeper shadow, on transform and
   opacity/shadow only — no layout properties, so nothing reflows on hover. */

/* Screenshots and clips. They are dark objects on a light page, so the lift
   plus a brighter rim reads as picking one up rather than as a colour change. */
.band video, .band img, .media-card img, .panel-shot img {
    transition: transform .32s cubic-bezier(.22,.61,.36,1),
                box-shadow .32s ease, border-color .32s ease;
}
.band:hover video, .band:hover img,
.media-card:hover img, .panel-shot:hover img {
    transform: translateY(-4px);
    box-shadow: 0 22px 44px -18px rgba(23,22,28,.55), var(--shadow-lg);
    border-color: #cfc7bd;
}

/* The three install steps are discrete cards, so they lift like cards. */
.steps li {
    transition: transform .3s cubic-bezier(.22,.61,.36,1), box-shadow .3s ease;
}
.steps li:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg); }

/* The battery figures are the same kind of object and were the last card-like
   group with no response at all. */
.stat { transition: transform .3s cubic-bezier(.22,.61,.36,1), box-shadow .3s ease; }
.stat:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg); }
/* FAQ rows are clickable and only the summary text changed colour, which is
   easy to miss. Tint the whole row so the hit area is obvious. */
.faq details { transition: background .25s ease; border-radius: 8px; }
.faq details:hover { background: var(--bg-lift); }

/* ------------------------------------------------------------------ table - */

table { width: 100%; border-collapse: collapse; margin: 1.5rem 0; font-size: .93rem; }
th, td { text-align: left; padding: .8rem .9rem; border-bottom: 1px solid var(--line); }
th { color: var(--ink); font-weight: 620; }
td { color: var(--ink-dim); }
.table-scroll { overflow-x: auto; }

/* ----------------------------------------------------------------- media -- */
/* Every screenshot here is of a dark menu bar. On a pale page they need a
   real edge or they read as holes punched in the layout. */

figure { margin: 2rem 0; }
figure img, .shots img {
    display: block; width: 100%; height: auto;
    border-radius: 10px; border: 1px solid var(--line);
    box-shadow: var(--shadow-lg); background: #14121a;
}
/* Full-bleed. These captures are 38:1 — the widest presentation possible is
   also the only one where the scene that distinguishes each theme is legible.
   Cropping them to fit a column erased exactly what the gallery exists to
   show: six themes that looked identical. */
.shots {
    display: grid; gap: 1.4rem; grid-template-columns: 1fr;
    margin-top: 2.5rem;
    width: 100vw; max-width: 100vw;
    margin-left: 50%; transform: translateX(-50%);
    padding: 0 1.5rem;
}
.shot-label {
    display: block; font-size: .78rem; letter-spacing: .1em; text-transform: uppercase;
    color: var(--ink-faint); font-weight: 620; margin: 0 0 .5rem;
}
.shot { margin: 0; }
.shot img { border-radius: 8px; }
.shots img { transition: transform .4s cubic-bezier(.22,.61,.36,1); }
.shots img:hover { transform: translateY(-5px) scale(1.01); }

/* The strip is 22:1 even after cropping. Side-by-side columns rendered it
   twelve pixels tall and unreadable, so each feature stacks: prose in a
   readable column, then its figure beneath. Do not "fix" this into two
   columns — the media is the reason it is not. */
.row { margin: 3.5rem 0 0; }
.row-text { max-width: var(--measure); }
.row-text h3 { font-size: 1.45rem; letter-spacing: -.03em; margin-bottom: .6rem; }
.row-text p { margin-bottom: 0; }

/* ------------------------------------------------------------------- misc - */

.note {
    border: 1px solid var(--line); border-left: 3px solid var(--accent);
    border-radius: 0 12px 12px 0; padding: 1.15rem 1.35rem;
    margin: 2rem 0; color: var(--ink-dim); font-size: .95rem;
    background: #fdf8ee;
}
code {
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: .88em; background: var(--bg-lift);
    padding: .15em .42em; border-radius: 5px; color: var(--ink);
    border: 1px solid var(--line);
}
.stat-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); gap: 1.1rem; margin: 2.5rem 0 0; }
.stat {
    border: 1px solid var(--line); border-radius: var(--radius);
    padding: 1.5rem 1.4rem; background: var(--bg-raised); box-shadow: var(--shadow);
}
.stat b {
    display: block; font-size: clamp(1.9rem, 4vw, 2.4rem); font-weight: 680;
    letter-spacing: -.04em; font-variant-numeric: tabular-nums;
    margin-bottom: .2rem; color: var(--ink);
}
.stat b:not([data-count]) { font-size: clamp(1.5rem, 3vw, 1.9rem); }
.stat span { color: var(--ink-faint); font-size: .85rem; }

.faq { margin-top: 2.5rem; border-top: 1px solid var(--line); }
.faq details { border-bottom: 1px solid var(--line); }
.faq summary {
    cursor: pointer; list-style: none; padding: 1.3rem 2.5rem 1.3rem 0;
    font-weight: 620; color: var(--ink); position: relative; font-size: 1.02rem;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
    content: "+"; position: absolute; right: .4rem; top: 50%;
    transform: translateY(-50%); font-size: 1.35rem; color: var(--ink-faint);
    font-weight: 400; transition: transform .25s ease, color .2s ease;
}
.faq details[open] summary::after { transform: translateY(-50%) rotate(45deg); color: var(--accent-deep); }
.faq details p { padding: 0 1rem 1.4rem 0; margin: 0; max-width: var(--measure); font-size: .95rem; }
.faq summary:hover { color: var(--accent-deep); }

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

.js .reveal {
    opacity: 0; transform: translateY(22px);
    transition: opacity .8s cubic-bezier(.22,.61,.36,1), transform .8s cubic-bezier(.22,.61,.36,1);
}
.reveal.in { opacity: 1; transform: none; }
/* Keyed off any reveal variant. Written as `.reveal.d1` these silently stopped
   matching the moment elements were renamed to reveal-s, and nine cards lost
   their cascade while still carrying the now-inert d1/d2 tokens. */
[class*="reveal"].d1 { transition-delay: .09s }
[class*="reveal"].d2 { transition-delay: .18s }
[class*="reveal"].d3 { transition-delay: .27s }
[class*="reveal"].d4 { transition-delay: .36s }

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    .reveal, .reveal.in { opacity: 1; transform: none; transition: none; }
    .card:hover, .shots img:hover, .btn:hover { transform: none; }
    .band:hover video, .band:hover img, .media-card:hover img,
    .panel-shot:hover img, .steps li:hover, .stat:hover { transform: none; }
    .shots img, .card, .btn { transition: none; }
}

@media (max-width: 40rem) {
    section { padding: 3.5rem 0; }
    .hero { padding: 3rem 0 .5rem; }
    .wrap { padding: 0 1.25rem; }
    header.site nav { gap: .95rem; }
    /* Hiding every link but Download left a phone visitor with exactly one
       way out of any page, and no route to Buy, Compatibility or Privacy
       without scrolling to the footer. The commercial pair stays; the
       on-page anchors are the ones that can go, since scrolling reaches
       those sections anyway. */
    header.site nav a[href^="#"] { display: none; }
    header.site nav a:not(.btn) { font-size: .86rem; }
    header.site nav { gap: .8rem; }
}

/* ======================================================= interactive demo = */
/* The pitch is spatial — "the Space to your left, the Space to your right" —
   and no still image conveys it. This is the product's own three-slot
   geometry driven by real state, so a visitor learns it by hopping. */

.demo { margin: 0 auto; max-width: 60rem; }

/* Ambient light under the machine, tinted by the active theme. It is what
   stops the lid reading as a flat rectangle pasted onto the page. */
.demo-stage {
    position: relative; padding: 0 0 1.5rem;
    /* The deck below is a real plane laid down in this perspective rather
       than a card drawn to look like one. Everything that made the old flat
       version convincing — the taper, the front edge being wider than the
       hinge — falls out of the projection for free, and correctly: the hinge
       is further away, so it is the narrower end. The hand-drawn taper had
       it backwards. */
    /* Gentle. A short perspective distance looks down at the machine, and
       the screen above is drawn straight-on — two different viewpoints in one
       object is what reads as wonky. Far camera, shallow tilt: the deck is a
       front edge with a little recession, which is all a head-on photo of a
       laptop actually shows. */
    perspective: 2800px;
    perspective-origin: 50% 28%;
}
/* Two lights, not one. The bloom is the screen throwing colour into the room
   around it; the pool below is that same light landing on the surface the
   machine sits on. Both take their colour from the active theme, so the whole
   picture changes together rather than the strip changing inside a static box. */
.demo-stage::before {
    content: ""; position: absolute; z-index: 0; pointer-events: none;
    left: 0; right: 0; top: 0; bottom: 8%;
    background: radial-gradient(66% 78% at 50% 46%, var(--glow, rgba(97,85,212,.5)), transparent 70%);
    filter: blur(46px); opacity: .14;
    transition: background .6s ease;
}
.demo-stage::after {
    content: ""; position: absolute; left: 8%; right: 8%; bottom: 0; height: 96px;
    background: radial-gradient(52% 100% at 50% 0%, var(--glow, rgba(97,85,212,.5)), transparent 72%);
    filter: blur(24px); opacity: .5; z-index: 0; pointer-events: none;
    transition: background .6s ease;
}

.demo-lid {
    position: relative; z-index: 1;
    transform-origin: center bottom;
    border-radius: 22px 22px 10px 10px;
    /* A chin, like the real machine. The screen used to run flush to the
       bottom edge, which is a monitor, not a laptop. */
    padding: 11px 11px 16px;
    background:
        linear-gradient(180deg, rgba(255,255,255,.22), rgba(255,255,255,0) 14%),
        linear-gradient(180deg, #6a6776 0%, #3b3945 22%, #26242e 60%, #1a1922 100%);
    /* Light that follows the machine's own edges. A box-shadow takes the
       shape of the box it is on, so tight low-blur layers trace the rectangle
       while the wide one carries that colour out into the room. A radial blob
       behind it read as a laptop sitting on a glow; this reads as a laptop
       that is lit. Every layer takes the active theme's colour. */
    box-shadow:
        0 0 18px -2px var(--glow, rgba(97,85,212,.55)),
        0 0 56px 2px var(--glow, rgba(97,85,212,.55)),
        0 2px 3px rgba(23,22,28,.30),
        0 34px 70px -26px rgba(23,22,28,.55),
        inset 0 1px 0 rgba(255,255,255,.30),
        inset 0 0 0 1px rgba(255,255,255,.07);
    transition: box-shadow .6s ease, transform .35s cubic-bezier(.22,.61,.36,1);
}
/* The deck. What used to sit here was a 9px stub standing in for everything
   below the screen, so the machine ended in mid-air and read as a monitor on
   a stand. This is the part that makes it a laptop: wider than the lid,
   tapering toward the viewer because the top surface recedes, with a bright
   milled edge where the aluminium catches the light and the finger cutout on
   the front lip.
   
   The taper is a clip-path, which also clips box-shadow — so the contact
   shadow is a drop-shadow filter instead, because that follows the shape it
   is given rather than the element's box. */
.demo-base {
    /* Above the lid, not behind it. The lid's box-shadow carries a wide
       coloured glow that was painting straight over the deck and washing the
       aluminium out to a flat smudge — and physically the front lip is the
       nearest part of the whole machine, so it belongs on top anyway. */
    position: relative; z-index: 2;
    /* Narrower than the lid at rest, because perspective widens the front
       edge — it lands roughly flush with the lid instead of flaring out past
       it like a wedge the machine is balanced on. */
    width: 99%; margin: 0 .5%;
    /* 72 degrees of a 56px-deep surface projects to about 17px. Steeper than
       this and the visible band thins to a line; shallower and you are
       looking down at a machine whose screen is drawn straight-on. */
    height: 56px;
    transform-origin: center top;
    transform: rotateX(72deg);
    /* Elliptical radii: the corners are foreshortened vertically along with
       everything else, so equal values would come back as flat nicks. */
    border-radius: 3px 3px 12px 12px / 3px 3px 40px 40px;
    /* Lit as a horizontal surface now, not a facing wall: darkest at the
       hinge where the lid shades it, opening out toward the front lip, and a
       hard bright line on the milled edge nearest the light. */
    background:
        linear-gradient(90deg, rgba(0,0,0,.42) 0%, rgba(0,0,0,0) 7%,
                               rgba(0,0,0,0) 93%, rgba(0,0,0,.42) 100%),
        linear-gradient(180deg,
            #16151c 0%, #26242c 10%, #45424e 30%,
            #6f6c7d 52%, #9b98ab 70%, #bdbacb 84%,
            #d6d3e0 94%, #efedf5 100%);
    /* The lid sits above this with a wide coloured glow in its box-shadow,
       and that wash flattens whatever is underneath it. The deck needs its
       own light to stay legible through it, hence the near-white front edge
       rather than the mid-grey that looked right in isolation. */
    box-shadow: 0 40px 34px -20px rgba(23,22,28,.7);
}
/* The hinge line, where the lid meets the deck. */
.demo-base::before {
    content: ""; position: absolute; left: 0; right: 0; top: 0; height: 2px;
    border-radius: 3px 3px 0 0;
    background: linear-gradient(180deg, rgba(0,0,0,.55), rgba(0,0,0,.15));
}
/* The cutout you get a fingertip into to open it. Taller than it looks —
   it is lying down in the same perspective as the surface it is cut into. */
.demo-base::after {
    content: ""; position: absolute; left: 50%; transform: translateX(-50%);
    bottom: 0; width: 11%; height: 16px;
    border-radius: 0 0 6px 6px / 0 0 18px 18px;
    background: linear-gradient(180deg, rgba(0,0,0,0), rgba(0,0,0,.5) 70%, rgba(0,0,0,.62));
}

.demo-screen {
    position: relative;
    /* Rounded on all four now that a chin sits below it. */
    border-radius: 13px; overflow: hidden;
    background: #05050a;
    /* Vignette: a real display falls off at its corners, and without it the
       scene sits perfectly flat and reads as a coloured rectangle. */
    box-shadow: inset 0 0 0 1px rgba(255,255,255,.06),
                inset 0 0 70px rgba(0,0,0,.55);
}
/* Glass. One soft diagonal band across the top left, the way a screen catches
   the light in a room. Above everything and click-through, so it never gets
   between a pointer and a pill. */
.demo-screen::after {
    content: ""; position: absolute; inset: 0; z-index: 6; pointer-events: none;
    background: linear-gradient(107deg,
        rgba(255,255,255,.075) 0%, rgba(255,255,255,.03) 22%,
        transparent 42%, transparent 100%);
}

.demo-bar {
    display: flex; align-items: stretch; height: 46px;
    position: relative; isolation: isolate;
    transition: background .6s ease;
}
.demo-side { flex: 1; display: flex; align-items: center; gap: 7px; padding: 0 14px; min-width: 0; overflow: hidden; }
.demo-side.left { justify-content: flex-end; }
.demo-side.right { justify-content: flex-start; }

/* The notch is hardware, so it stays the darkest thing on screen — but it now
   takes a tint from the active theme instead of sitting as a dead black slab
   that ignores every colour around it. */
.demo-notch {
    width: 168px; flex: none; z-index: 2;
    border-radius: 0 0 14px 14px;
    background: var(--notch, #04040a);
    box-shadow: inset 0 -1px 0 rgba(255,255,255,.05);
    transition: background .6s ease;
}

.dpill {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 5px 12px 5px 6px; border-radius: 999px; cursor: pointer;
    background: var(--fill, rgba(255,255,255,.10));
    border: 1px solid rgba(255,255,255,.16);
    box-shadow: inset 0 1px 0 rgba(255,255,255,.18), 0 1px 3px rgba(0,0,0,.35);
    color: #fbfaff; white-space: nowrap;
    font-size: 11.5px; font-weight: 600; letter-spacing: -.01em;
    transition: filter .18s ease, border-color .18s ease;
}
.dpill:hover { filter: brightness(1.22); border-color: rgba(255,255,255,.4); }
.dpill:active { filter: brightness(.95); }
.dpill .ic {
    width: 17px; height: 17px; border-radius: 5px; flex: none;
    display: grid; place-items: center; font-size: 10px; line-height: 1;
    box-shadow: inset 0 1px 0 rgba(255,255,255,.35), 0 1px 2px rgba(0,0,0,.3);
}
.dpill .ic + .ic { margin-left: -3px; }

/* A replica of the app's own transition, read out of
   OverlayView.chipTransition: "bubble" is scale(0.3) + opacity, made
   direction-aware so pills flow WITH the macOS slide — in from the trailing
   edge moving right, the leading edge moving left, out the opposite way. */
.demo-bar.go-right .dpill { animation: pill-in-right .44s cubic-bezier(.2,.9,.3,1.08) backwards; }
.demo-bar.go-left  .dpill { animation: pill-in-left  .44s cubic-bezier(.2,.9,.3,1.08) backwards; }
.dpill.leaving { pointer-events: none; }
.demo-bar.go-right .dpill.leaving { animation: pill-out-left  .26s cubic-bezier(.4,0,.7,.3) forwards; }
.demo-bar.go-left  .dpill.leaving { animation: pill-out-right .26s cubic-bezier(.4,0,.7,.3) forwards; }
@keyframes pill-in-right { from { opacity: 0; transform: translateX(36px) scale(.3) } to { opacity: 1; transform: none } }
@keyframes pill-in-left  { from { opacity: 0; transform: translateX(-36px) scale(.3) } to { opacity: 1; transform: none } }
@keyframes pill-out-left  { to { opacity: 0; transform: translateX(-30px) scale(.3) } }
@keyframes pill-out-right { to { opacity: 0; transform: translateX(30px) scale(.3) } }
/* Ripples outward from the notch rather than moving as a block — `cascade`. */
.demo-side.left  .dpill:nth-last-child(1),
.demo-side.right .dpill:nth-child(1) { animation-delay: 0s }
.demo-side.left  .dpill:nth-last-child(2),
.demo-side.right .dpill:nth-child(2) { animation-delay: .055s }

/* The screen below the bar. Shallow — it is a laptop lid, not a monitor. */
.demo-desk {
    height: clamp(150px, 20vw, 210px);
    display: grid; place-items: center; align-content: center; gap: .35rem;
    background: var(--desk, radial-gradient(90% 130% at 50% 0%, #1d2440 0%, #05050a 72%));
    transition: background .6s ease;
    position: relative;
}
/* The light in the room comes from the strip, so the desk is brightest just
   under it and falls away downward. */
.demo-desk::after {
    content: ""; position: absolute; inset: 0; z-index: 3; pointer-events: none;
    background:
        radial-gradient(70% 90% at 50% -10%, rgba(255,255,255,.10), transparent 62%),
        linear-gradient(180deg, rgba(255,255,255,.05), transparent 34%),
        linear-gradient(180deg, transparent 55%, rgba(0,0,0,.35) 100%);
}
.demo-desk .now {
    font-size: clamp(1.6rem, 3.6vw, 2.2rem); font-weight: 680;
    letter-spacing: -.035em; color: #fff;
    /* Lit from above like everything else on this screen. */
    text-shadow: 0 1px 0 rgba(255,255,255,.18), 0 6px 28px rgba(0,0,0,.55);
}
.demo-desk .sub {
    font-size: .7rem; color: rgba(255,255,255,.5);
    letter-spacing: .18em; text-transform: uppercase; font-weight: 620;
}

/* Theme picker */
.demo-themes {
    display: flex; gap: .5rem; justify-content: center;
    margin-top: 2.25rem; flex-wrap: wrap; row-gap: .6rem;
}
.demo-swatch {
    display: inline-flex; align-items: center; gap: .45rem; font-size: .8rem;
    /* flex: none, or seven of these shrink below their own labels and the
       text overlaps into an unreadable pile. Wrapping is the correct
       response to a narrow row, not squeezing. */
    flex: none; white-space: nowrap;
    height: 32px; padding: 0 .8rem; border-radius: 999px; cursor: pointer;
    border: 1px solid var(--line); background: var(--bg-raised);
    color: var(--ink-dim); font: inherit; font-size: .82rem; font-weight: 580;
    box-shadow: var(--shadow);
    transition: transform .16s ease, box-shadow .16s ease, color .16s ease, border-color .16s ease;
}
.demo-swatch:hover { transform: translateY(-2px); box-shadow: var(--shadow-lg); color: var(--ink); }
.demo-swatch[aria-pressed="true"] {
    color: var(--ink); border-color: var(--ink); background: var(--bg-raised);
    box-shadow: 0 0 0 1px var(--ink), var(--shadow);
}

.demo-hint { text-align: center; margin: 1.1rem 0 0; font-size: .86rem; color: var(--ink-faint); }
.demo-hint kbd {
    font: inherit; border: 1px solid var(--line); border-bottom-width: 2px;
    border-radius: 5px; padding: .1em .45em; background: var(--bg-raised); color: var(--ink-dim);
}

/* ------------------------------------------------------------- demo scenes */
/* Real artwork, cropped pill-free from the same captures the gallery shows
   (Support/crop-strip.swift), and cross-faded rather than swapped.
   background-image cannot be transitioned in CSS at all, so a class swap
   snapped from one theme to the next however long the transition said. Two
   stacked layers, fading opposite ways, is the only way to morph one picture
   into another — and opacity is compositable, so it costs nothing. */
.scene-layer {
    position: absolute; inset: 0; z-index: 0;
    background-repeat: repeat-x;
    background-size: auto 100%;
    background-position: left center;
    opacity: 0;
    transition: opacity .55s cubic-bezier(.4,0,.2,1);
}
.scene-layer.on { opacity: 1; }
/* Some scenes repeat and tile cleanly; others are ONE sweep across the whole
   strip, and tiling those restarts the sweep at every repeat — Summit's ridge
   climbed then snapped back over and over, a sawtooth in no real theme. */
.scene-layer.sweep { background-repeat: no-repeat; background-size: 100% 100%; }

/* The desk below morphs the same way, or the bar would cross-fade while the
   screen under it jumped. */
.desk-layer {
    position: absolute; inset: 0;
    opacity: 0;
    transition: opacity .55s cubic-bezier(.4,0,.2,1);
}
.desk-layer.on { opacity: 1; }

/* Pills and the notch sit above both layers. */
.demo-side, .demo-notch { position: relative; z-index: 2; }
.demo-desk .now, .demo-desk .sub { position: relative; z-index: 2; }

/* ====================================================== scroll behaviour == */
/* Everything here is transform and opacity only, driven by ONE rAF-throttled
   listener and one IntersectionObserver. A page whose headline claim is
   "0.0% CPU while idle" cannot stutter while making it. */

/* Reading progress, hairline under the sticky header. */
.progress {
    position: fixed; top: 0; left: 0; height: 2px; z-index: 30;
    width: 100%; transform: scaleX(var(--p, 0)); transform-origin: 0 50%;
    background: linear-gradient(90deg, var(--accent), var(--accent-2));
    pointer-events: none;
}

/* Directional entrances. Sideways for things that sit in a row, so the eye
   is led along the row rather than having each item pop in place. */
.js .reveal-l, .js .reveal-r {
    opacity: 0;
    transition: opacity .85s cubic-bezier(.22,.61,.36,1), transform .85s cubic-bezier(.22,.61,.36,1);
}
.reveal-l { transform: translateX(-38px); }
.reveal-r { transform: translateX(38px); }
.reveal-l.in, .reveal-r.in { opacity: 1; transform: none; }

/* Scale-in, for the blocks that should feel like they arrive rather than slide. */
.js .reveal-s { opacity: 0; transform: scale(.965) translateY(20px);
    transition: opacity .8s cubic-bezier(.22,.61,.36,1), transform .8s cubic-bezier(.22,.61,.36,1); }
.reveal-s.in { opacity: 1; transform: none; }

/* Parallax drift. Small numbers on purpose: anything stronger and the page
   starts to feel like it is fighting the scroll wheel. */
[data-drift] { will-change: transform; }

/* The hero settles back and fades as you leave it, so the demo below takes
   over rather than the two competing for attention. */
.hero { transform: translateY(var(--heroY, 0)); opacity: var(--heroO, 1); }


@media (prefers-reduced-motion: reduce) {
    .reveal-l, .reveal-r, .reveal-s,
    .reveal-l.in, .reveal-r.in, .reveal-s.in { opacity: 1; transform: none; transition: none; }
    [data-drift] { transform: none !important; }
    .hero { transform: none !important; opacity: 1 !important; }
    h2.reveal.in { animation: none; }
    .progress { display: none; }
}

/* Replaces an inline style attribute. The site's own CSP is `style-src 'self'`
   with no 'unsafe-inline', so inline style attributes are dropped in
   production while working fine over a local preview — a discrepancy that
   would never show up in make site-serve. */
.spaced-top { margin-top: 1.75rem; }

/* ================================================== keyboard and a11y ==== */
/* There were no focus styles at all, which meant tabbing through the site was
   invisible — every link, button, FAQ toggle and demo pill gave no indication
   of where you were. :focus-visible rather than :focus so it appears for
   keyboard users without ringing every mouse click. */
:where(a, button, summary, [tabindex]):focus-visible {
    outline: 2px solid var(--accent-2);
    outline-offset: 3px;
    border-radius: 6px;
}
/* Inside the dark lid the violet ring disappears; white reads on any scene. */
.demo :where(button):focus-visible { outline-color: #fff; outline-offset: 2px; }

/* Skip link: a keyboard user should not have to tab the whole header on every
   page to reach the content. Off-screen until focused. */
.skip {
    position: absolute; left: 50%; top: 0; transform: translate(-50%, -120%);
    z-index: 50; background: var(--bg-raised); color: var(--ink);
    border: 1px solid var(--line); border-radius: 0 0 10px 10px;
    padding: .7rem 1.2rem; font-weight: 620; text-decoration: none;
    transition: transform .18s ease;
}
.skip:focus-visible { transform: translate(-50%, 0); outline-offset: -2px; }

/* The FAQ rows are the one place a pointer is not obviously a button. */
.faq summary:focus-visible { outline-offset: -2px; }

/* Without intrinsic dimensions an <img> is zero-height until its bytes land,
   so the reveal animated an empty box and the page jumped when it filled. The
   width/height attributes give the browser the ratio up front; aspect-ratio
   here is the belt to that pair of braces, and matters for the theme strips
   most because they are 44:1 and collapse to nothing. */
figure img, .shots img, .media-card img { aspect-ratio: attr(width) / attr(height); }

/* --------------------------------------------------------------- media --- */
/* `width: 100%` on a <video> is load-bearing: without it the element renders
   at its intrinsic size — 3018px here — which is wider than the container and
   pushes the whole page sideways. */
/* Two media treatments, and only two. `.band` is anything shaped like the
   strip — 22:1 or wider, where the only readable presentation is full column
   width. `.media-card` is anything shaped like an object: a panel, a preview
   card, something photographed close up. Every figure on the page is one or
   the other, which is what stops them reading as unrelated blocks dropped
   near the prose.

   Each band declares its own ratio, because that is what reserves the right
   height before the video loads. One shared value squashed whichever clip did
   not own it. */
.band { margin: 1.5rem 0 0; }
.band video, .band img {
    display: block; width: 100%; height: auto; max-width: 100%;
    border-radius: 10px; border: 1px solid var(--line);
    box-shadow: var(--shadow-lg); background: #0a0910;
}
.band video { aspect-ratio: 1512 / 40; }
.band.map video { aspect-ratio: 3018 / 134; }
.band.pets video { aspect-ratio: 3028 / 68; }
.shots img { aspect-ratio: 3028 / 68; }

.media-card { margin: 1.5rem 0 0; }
.media-card img {
    display: block; width: 100%; max-width: 33rem; height: auto;
    border-radius: 10px; border: 1px solid var(--line);
    box-shadow: var(--shadow-lg);
}

/* Captions are what turn a column of pictures into a tour: every figure says
   what it is. The dot marks the ones that are recordings rather than stills,
   so "this actually moves" is legible before you notice it moving. */
figcaption, .band figcaption, .media-card figcaption {
    color: var(--ink-faint); font-size: .85rem; margin-top: .7rem;
    max-width: var(--measure);
}
figcaption.rec { display: flex; align-items: center; gap: .45rem; }
figcaption.rec::before {
    content: ""; width: 6px; height: 6px; border-radius: 50%;
    background: var(--ok); flex: none;
}

/* The download button's lid-and-notch glyph. currentColor so it inherits the
   button's ink in both the primary and hover states, and a fixed size so it
   never scales with the surrounding text. */
.mac-ico { width: 15px; height: 15px; flex: none; display: block; }
.btn .mac-ico { margin-right: -.1rem; }
header.site nav a.btn { padding: .5rem 1rem; font-size: .9rem; }
@media (max-width: 40rem) {
    header.site nav a.btn { padding: .45rem .8rem; }
}


/* ==================================================== bento ============== */
/* Six identical rectangles in a row was the page's third uniform grid in a
   row, and the eye stops reading them as separate things. Varying the cell
   sizes gives the section a shape of its own and lets the biggest claim carry
   the artwork that proves it. */
.bento {
    display: grid; gap: 1rem; margin-top: 2.5rem;
    grid-template-columns: repeat(6, 1fr);
}
.bento > * {
    border: 1px solid var(--line); border-radius: var(--radius);
    background: var(--bg-raised); box-shadow: var(--shadow);
    padding: 1.6rem 1.5rem;
    transition: transform .3s cubic-bezier(.22,.61,.36,1), box-shadow .3s ease;
}
.bento > *:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg); }
.bento h3 { margin-bottom: .4rem; }
.bento p { margin-bottom: 0; font-size: .93rem; }
.b-4 { grid-column: span 4; } .b-3 { grid-column: span 3; }
.b-2 { grid-column: span 2; } .b-6 { grid-column: span 6; }

/* The count leads, because "51" does more work than any sentence about it. */
.bento .figure {
    display: block; font-size: clamp(2.2rem, 5vw, 3rem); font-weight: 680;
    letter-spacing: -.04em; line-height: 1; margin-bottom: .5rem; color: var(--ink);
}
.bento .figure small {
    display: block; font-size: .72rem; letter-spacing: .14em; margin-top: .45rem;
    text-transform: uppercase; color: var(--ink-faint); font-weight: 620;
}
/* Proof rather than assertion: the wide cell carries real strips. */
.bento .swatch-row { display: flex; gap: .4rem; margin-top: 1rem; flex-wrap: wrap; }
.bento .swatch-row i {
    width: 26px; height: 18px; border-radius: 5px; display: block;
    border: 1px solid rgba(0,0,0,.12);
}
@media (max-width: 56rem) {
    .bento { grid-template-columns: repeat(2, 1fr); }
    .b-4, .b-3, .b-2, .b-6 { grid-column: span 2; }
}

/* ================================================== feature list ========= */
/* Six equal cards wrapped to four-then-two, which reads as a mistake rather
   than a layout. Rebalancing to 3x2 would have fixed the count and left the
   page with three boxed grids in a row, so these lose their boxes entirely:
   a hairline-divided list, title on the left, explanation on the right. Calm
   where the bento below is busy, and it can hold any number of rows without
   the last one looking orphaned. */
.flist { margin-top: 2.5rem; border-top: 1px solid var(--line); }
.flist > div {
    display: grid; grid-template-columns: 15rem 1fr; gap: 2.5rem;
    padding: 1.6rem 0; border-bottom: 1px solid var(--line);
    align-items: start;
}
.flist .lead-col { display: flex; align-items: center; gap: .75rem; }
.flist h3 { margin: 0; font-size: 1.05rem; }
.flist p { margin: 0; font-size: .95rem; max-width: 34rem; }
.flist .ico {
    display: grid; place-items: center; flex: none;
    width: 34px; height: 34px; border-radius: 9px; font-size: 1rem;
    background: #f1eefc; border: 1px solid #e2ddf7;
}
/* The row lifts its title rather than the whole block, so scanning down the
   left column feels like a list rather than a stack of buttons. */
.flist > div:hover .lead-col { transform: translateX(3px); }
.flist .lead-col { transition: transform .25s cubic-bezier(.22,.61,.36,1); }

@media (max-width: 46rem) {
    .flist > div { grid-template-columns: 1fr; gap: .6rem; padding: 1.3rem 0; }
    .flist p { max-width: none; }
}
@media (prefers-reduced-motion: reduce) {
    .flist .lead-col, .flist > div:hover .lead-col { transform: none; transition: none; }
}

/* Leaving is quicker than arriving. An entrance wants to feel considered; an
   exit is something you scrolled away from, and matching the 0.8s inbound
   timing made the page feel like it was dragging behind the wheel. */
.reveal, .reveal-l, .reveal-r, .reveal-s {
    transition-duration: .38s;
}
.reveal.in, .reveal-l.in, .reveal-r.in, .reveal-s.in {
    transition-duration: .8s;
}

/* Sits under the full-bleed gallery, so it needs its own centring rather than
   inheriting the strip row's edge-to-edge width. */
/* The gallery, shown rather than asserted. Nine strips above prove the themes
   differ from each other; this proves there are fifty-one of them, which is a
   claim a row of strips cannot make on its own. Masked at the foot so the
   panel reads as continuing past the crop rather than having been cut off —
   which is the truth, the list keeps going. */
.gallery-proof {
    display: grid; grid-template-columns: minmax(0, 19rem) 1fr;
    gap: 2.75rem; align-items: center; margin: 3.5rem 0 0;
}
.panel-shot { margin: 0; }
.panel-shot img {
    display: block; width: 100%; height: auto;
    border-radius: 12px; box-shadow: var(--shadow-lg);
    -webkit-mask-image: linear-gradient(#000 86%, transparent 100%);
    mask-image: linear-gradient(#000 86%, transparent 100%);
}
.gallery-copy h3 {
    font-size: 1.45rem; letter-spacing: -.03em; margin-bottom: .6rem;
}
.gallery-copy p { max-width: var(--measure); }
.gallery-copy p:last-child { margin-bottom: 0; color: var(--ink-dim); }
@media (max-width: 46rem) {
    .gallery-proof { grid-template-columns: 1fr; gap: 1.75rem; }
    .panel-shot { max-width: 19rem; margin: 0 auto; }
}

/* A faint reflection under the machine, as though it were standing on
   something with a sheen. Fades out fast: any more and it stops reading as a
   surface and starts reading as a second, upside-down laptop. */
.demo-stage { padding-bottom: 3rem; }
.demo-lid::before {
    content: ""; position: absolute; z-index: -1;
    left: 8%; right: 8%; top: 100%; height: 38px;
    background: linear-gradient(180deg, rgba(90,87,100,.30), transparent 72%);
    filter: blur(7px);
    border-radius: 0 0 18px 18px;
}

/* ================================================== demo panel =========== */
/* The demo used to float between the hero and the features with nothing
   framing it, so it read as a screenshot rather than something to touch. The
   panel gives it a stage: its own ground, its own heading, and enough room
   around the machine that the ambient light has somewhere to fall. */
.demo-panel {
    position: relative; overflow: hidden;
    margin: 3.5rem 0 0;
    /* Roomier at the top than the bottom: the machine's own shadow and
       reflection already occupy space below it, so equal padding reads as
       bottom-heavy. */
    padding: 2.75rem 2.5rem 2rem;
    border-radius: 26px;
    border: 1px solid var(--line);
    background:
        radial-gradient(70% 50% at 50% 52%, var(--glow, rgba(97,85,212,.5)), transparent 55%),
        radial-gradient(90% 70% at 50% 0%, #fffdf8, transparent 60%),
        linear-gradient(180deg, #f7f4ef 0%, #fbfaf8 60%);
    transition: background .6s ease;
    box-shadow: 0 1px 2px rgba(23,22,28,.04), 0 40px 90px -50px rgba(23,22,28,.30);
}
/* A hairline of the brand across the top edge, so the panel reads as a
   deliberate surface rather than a lighter rectangle. */
.demo-panel::before {
    content: ""; position: absolute; inset: 0 0 auto; height: 1px;
    background: linear-gradient(90deg, transparent, var(--accent) 30%, var(--accent-2) 70%, transparent);
    opacity: .55;
}
.demo-head { text-align: center; max-width: 34rem; margin: 0 auto 2.25rem; }
.demo-head h2 { margin-bottom: .6rem; }
.demo-head p { margin: 0; font-size: .98rem; }
.demo-head .eyebrow { margin-bottom: 1rem; }


/* Hint and theme picker on one line where there is room, so the controls read
   as one bar under the machine rather than two stacked rows. */
/* Stacked, not side by side. Sharing a line with the hint left the eight
   chips about 800px in roughly 800px of room, so they wrapped to a second row
   the moment a theme name ran long — and a control that reflows as you rename
   things is a control that will break again. On its own line the row has the
   full panel width and eight fit comfortably. */
.demo-foot {
    display: flex; flex-direction: column; align-items: center;
    gap: .9rem; margin-top: 1.5rem;
    padding-top: 1.4rem; border-top: 1px solid var(--line);
}
.demo-foot .demo-hint { margin: 0; text-align: center; order: 2; }
.demo-foot .demo-themes {
    margin: 0; order: 1; justify-content: center;
    flex-wrap: nowrap; max-width: 100%;
    /* Narrow windows scroll the row rather than stacking it: two rows of
       chips is the thing being fixed, so it must not come back on a phone. */
    overflow-x: auto; scrollbar-width: none;
    padding: 4px 2px 5px;
}
.demo-foot .demo-themes::-webkit-scrollbar { display: none; }

@media (max-width: 46rem) {
    .demo-panel { padding: 2rem 1.1rem 1.6rem; border-radius: 20px; }
    .demo-foot { justify-content: center; }
    .demo-foot .demo-hint { text-align: center; flex: 1 1 100%; }
    .demo-foot .demo-themes { justify-content: center; }
}

/* ================================================== maker =============== */
/* A letter, so it is set like one: a narrower measure than the rest of the
   page, more air between lines, and paragraphs far enough apart to be read as
   separate thoughts rather than a wall. Around 62 characters a line is where
   prose stops being work. */
.maker { max-width: 33rem; margin: 0 auto; }
.maker h2 { text-align: center; margin-bottom: 1.75rem; }
.maker p {
    font-size: 1.06rem;
    line-height: 1.85;
    margin-bottom: 1.5rem;
    color: var(--ink-dim);
}
.maker p:last-child { margin-bottom: 0; }
/* The first line carries the story, so it gets the darker ink. */
.maker p:first-of-type { color: var(--ink); }
.maker a { font-weight: 560; white-space: nowrap; }

@media (max-width: 40rem) {
    .maker p { font-size: 1rem; line-height: 1.75; }
}

/* Without JavaScript the demo cannot populate itself, so the panel is hidden
   rather than shown empty: a blank laptop lid is worse than no laptop. The
   rest of the page is plain HTML and reads normally. */
.no-js .demo-panel { display: none; }
.no-js .reveal, .no-js .reveal-l, .no-js .reveal-r, .no-js .reveal-s {
    opacity: 1; transform: none;
}

/* ================================================== assurance =========== */
/* On a direct-sale Mac app the first question is not what it does, it is
   whether it is safe to run. The answer here is genuinely strong, so it says
   so where the question gets asked: under the hero buttons, again once the
   features have made their case, and once more at the price. */
.tick { width: 15px; height: 15px; flex: none; color: var(--ok); }

.trust {
    list-style: none; padding: 0; margin: 1.5rem 0 0;
    display: flex; gap: 1.4rem; flex-wrap: wrap; justify-content: center;
}
.trust li {
    display: inline-flex; align-items: center; gap: .45rem;
    margin: 0; font-size: .86rem; color: var(--ink-dim); font-weight: 550;
}

.assurance { padding: 0; }
.assurance-inner {
    display: grid; grid-template-columns: auto 1fr; gap: .3rem .7rem;
    align-items: start;
    max-width: 44rem; margin: 0 auto;
    padding: 1.4rem 1.6rem;
    border: 1px solid var(--line); border-radius: var(--radius);
    background: linear-gradient(180deg, #f4fbf6, var(--bg-raised));
    font-weight: 620; color: var(--ink); font-size: 1rem;
}
.assurance-inner .tick { margin-top: .18rem; }
.assurance-inner span {
    grid-column: 2; font-weight: 400; color: var(--ink-dim);
    font-size: .93rem; line-height: 1.6;
}

/* On the price cards it is a footnote, not a headline: by then it should
   reassure rather than argue. */
.assured {
    display: flex; align-items: center; gap: .4rem;
    margin: 0; font-size: .84rem; color: var(--ink-faint); font-weight: 550;
}
.assured .tick { width: 13px; height: 13px; }

.faq details ul { margin: .2rem 0 1rem; }
.faq details .table-scroll { margin: .2rem 0 1.2rem; }

/* ============================================ more scroll motion ======== */
/* A rule that draws itself under each section heading as it arrives. Only
   transform, so it stays on the compositor, and it gives every section a small
   moment of its own rather than headings simply appearing. */
.js h2.reveal::after,
.js h2.reveal-l::after,
.js h2.reveal-s::after {
    content: ""; display: block; height: 2px; width: 3.5rem;
    margin-top: .85rem; border-radius: 2px;
    background: linear-gradient(90deg, var(--accent), var(--accent-2));
    transform: scaleX(0); transform-origin: 0 50%;
    transition: transform .7s cubic-bezier(.22,.61,.36,1) .18s;
}
.js h2.reveal.in::after,
.js h2.reveal-l.in::after,
.js h2.reveal-s.in::after { transform: scaleX(1); }
/* Centred sections centre their rule too. */
.js .maker h2.reveal::after,
.js .demo-head h2::after,
.js section.center h2.reveal::after { margin-left: auto; margin-right: auto; transform-origin: 50% 50%; }

/* A fourth stagger step, for the FAQ rows. */
[class*="reveal"].d3 { transition-delay: .27s }

/* The assurance panel arrives with a touch of scale, so the one block whose
   job is reassurance does not simply blink into place. */
.js .assurance-inner { transition: transform .7s cubic-bezier(.22,.61,.36,1); }
.js .assurance.reveal-s:not(.in) .assurance-inner { transform: scale(.97); }

/* The footer is the last thing on the page; letting it fade up stops the
   scroll ending on an abrupt edge. */
.js footer.site.reveal { transition-duration: .6s; }

@media (prefers-reduced-motion: reduce) {
    .js h2.reveal::after, .js h2.reveal-l::after, .js h2.reveal-s::after {
        transform: scaleX(1); transition: none;
    }
    .js .assurance-inner { transform: none !important; transition: none; }
}
