/* Ring Glance pages (/apps/ring-glance, /faq, /privacy) — the app's own
   visual identity, self-contained (redesigned 2026-07-11, replacing the first
   synthwave-chrome draft; decisions recorded in the visual-direction session):
   warm OLED near-black + cream (the app brand), Hanken Grotesk throughout
   (labels a notch heavier), no icons — type does the work — and two live behaviors:
   the hero eye's pupil follows the cursor, and the theme swatches retint the
   page accent, which starts NEUTRAL cream until the visitor picks.
   Deliberately independent of site.css so these pages can lift out to their
   own domain nearly copy-paste; Nakhla appears only as the footer imprint.
   Every user-facing string in the HTML is VERBATIM from
   RingGlance/docs/ops/android/play-listing.md §4/§5 (pinned by
   tests/ring-glance.spec.ts) — change the copy there first, never here. */
:root{
  --rg-bg:#131110;
  --rg-panel:#1A1815;
  --rg-ink:#ECE7DB;
  --rg-dim:rgba(236,231,219,.62);
  --rg-faint:rgba(236,231,219,.38);
  --rg-line:rgba(236,231,219,.13);
  /* The live accent. Neutral cream until a theme is chosen — the pick is the
     moment the page takes color (mirrors the app's own theme picker, P8). */
  --rg-accent:#ECE7DB;
  /* The accent as body-copy tint (tagline, card titles): one token so the
     two stay visually locked; resolves live when --rg-accent changes. */
  --rg-accent-copy:color-mix(in srgb,var(--rg-accent) 75%,var(--rg-ink));
  /* Labels/eyebrows/pills/nav/footer wear the body family (Hanken Grotesk),
     one notch heavier for presence at small tracked-caps sizes. Fragment Mono
     was dropped 2026-07-13: the tracked-uppercase mono eyebrow is the current
     codegen-landing-page tell, and nothing on the page is genuinely tabular
     (the watch numbers live baked into the shot PNGs), so the mono earned its
     keep nowhere. One family reads as one intentional voice. */
  --rg-label-font:'Hanken Grotesk',sans-serif;
  --rg-label-weight:600;
  /* The watch-bezel metal. One token (review, 2026-07-13): the strips'
     half-bezels, both fixed carousel rings, the tile discs, and the face
     cards' bezels must all read as the same hardware — retuning the finish
     here reaches every one. */
  --rg-bezel:linear-gradient(160deg,#3B352E,#191512 52%,#26221C);
  /* The rim highlight every round/half bezel shares (review, 2026-07-13). */
  --rg-bezel-sheen:inset 0 2px 0 rgba(236,231,219,.05);
  /* The bezel ring THICKNESS (PR #12 review): the tiles band derives every
     11px/22px from this token so the title svg's box can't drift from the
     tile's padding — a mismatch there re-opens the Safari inset-box bug
     (see .rg-tile-title). The shots/faces bezels still carry 11px literals;
     adopt the token there on the next retune. */
  --rg-bezel-pad:11px;
}
*{box-sizing:border-box}
body{margin:0;background:var(--rg-bg);color:var(--rg-ink);font-family:'Hanken Grotesk',sans-serif;font-size:16px;line-height:1.6;-webkit-font-smoothing:antialiased}
.rg-wrap{max-width:1060px;margin:0 auto;padding:0 24px}
a{color:var(--rg-ink)}
a:focus-visible,button:focus-visible{outline:2px solid var(--rg-accent);outline-offset:3px;border-radius:4px}

.rg-label{font-family:var(--rg-label-font);font-weight:var(--rg-label-weight);font-size:11px;letter-spacing:.2em;text-transform:uppercase;color:var(--rg-accent);transition:color .25s}
.rg-note{font-family:var(--rg-label-font);font-weight:var(--rg-label-weight);font-size:12px;line-height:1.8;color:var(--rg-dim)}

/* ---- header: the wordmark, a couple of quiet links ---- */
.rg-header{position:sticky;top:0;z-index:50;background:rgba(19,17,16,.86);backdrop-filter:blur(8px);border-bottom:1px solid var(--rg-line)}
.rg-header .rg-wrap{display:flex;align-items:center;gap:20px;padding-top:12px;padding-bottom:12px}
.rg-header .rg-spring{flex:1}
.rg-header a.rg-navlink{font-family:var(--rg-label-font);font-weight:var(--rg-label-weight);font-size:11px;letter-spacing:.16em;text-transform:uppercase;text-decoration:none;color:var(--rg-dim)}
.rg-header a.rg-navlink:hover{color:var(--rg-ink)}
.rg-header a.rg-navlink[aria-current="page"]{color:var(--rg-ink);text-decoration:underline;text-underline-offset:5px;text-decoration-color:var(--rg-dim)}
/* Homepage live lockup: hidden while the hero title is on screen, rises in
   once it scrolls away (toggled by IntersectionObserver on [data-hero-title]) */
.rg-header .rg-lockup{display:flex;align-items:center;gap:10px;text-decoration:none;transition:opacity .4s,transform .4s,visibility 0s 0s}
.rg-header .rg-lockup .rg-eye{width:30px}
.rg-header .rg-lockup-name{font-weight:800;font-size:19px;letter-spacing:-.01em;color:var(--rg-ink)}
.rg-header .rg-lockup.rg-lockup-hidden{opacity:0;transform:translateY(14px);visibility:hidden;transition:opacity .4s,transform .4s,visibility 0s .4s}

/* ---- hero ---- */
.rg-hero{background:radial-gradient(110% 140% at 50% -30%,color-mix(in srgb,var(--rg-accent) 7%,#221E19) 0%,var(--rg-panel) 50%,#0F0D0B 100%);border-bottom:1px solid var(--rg-line);padding:80px 0 72px}
/* Hero split (2026-07-13): copy left, the watch right — the wide hero was
   a dark void past the copy with no product imagery above the fold. The
   watch drops out below ~920px, where the copy needs the full width.
   Ring = --hw/19, the tiles strip's exact bezel-to-dial ratio (11/210 ≈
   5.2%) — a fixed 13px ring at this size read as a thin border, not watch
   hardware (Jonathan's "ratio" catch). The JS cycles the dial through the
   tiles + a Night-face frame, in whatever theme the picker below has
   chosen (the hero joined the swap 2026-07-13; hint: "the whole page"). */
.rg-hero-split{display:flex;align-items:center;gap:clamp(36px,6vw,110px)}
.rg-hero-copy{flex:1 1 auto;min-width:0}
.rg-hero-watch{flex:0 0 auto}
/* Explicit height, NOT aspect-ratio:1 (Jonathan's oval catch, 2026-07-13):
   WebKit resolves aspect-ratio against the CONTENT box even under
   box-sizing:border-box, so with this element's padding Safari rendered
   the bezel padding-taller than wide. Both dimensions are the same var —
   nothing needed deriving anyway. */
.rg-hero-bezel{--hw:clamp(250px,26vw,340px);position:relative;width:var(--hw);height:var(--hw);padding:calc(var(--hw)/19);background:var(--rg-bezel);border-radius:50%;box-shadow:0 30px 60px -28px rgba(0,0,0,.9),var(--rg-bezel-sheen)}
.rg-hero-bezel img{display:block;width:100%;height:100%;border-radius:50%;background:#000}
/* The cycler's crossfade ghost (same dissolve grammar as the theme swap;
   sized by JS since % widths resolve against the bezel's padding box). */
.rg-hero-bezel img.rg-swap-ghost{position:absolute;pointer-events:none;transition:opacity .5s}
@media(max-width:919px){.rg-hero-watch{display:none}}
.rg-eye{height:auto;flex-shrink:0}
/* transform-box/origin: the poke-egg squint (inline JS) scales the pupil
   around its own current center, wherever the follower has put it. Static
   geometry, not motion — the reduce block leaves it alone. */
.rg-eye .rg-pupil{fill:var(--rg-accent);transition:fill .25s;transform-box:fill-box;transform-origin:center}
/* Title row: the eye sits inline with the name at every width, so narrow
   screens never orphan the mark above the copy (2026-07-12 hero rework). */
.rg-hero-title{display:flex;align-items:center;gap:clamp(16px,3.4vw,34px)}
/* touch-action + tap-highlight: the poke egg invites RAPID tapping — without
   manipulation iOS reads the second quick poke as double-tap-to-zoom, and
   each tap flashes the grey highlight over the mark's box (same class of
   fix as the holograms' 5fd1da0). Hero only; the header eye is a nav link. */
.rg-hero-title .rg-eye{width:clamp(64px,11vw,118px);filter:drop-shadow(0 0 34px color-mix(in srgb,var(--rg-accent) 26%,transparent));transition:filter .25s;touch-action:manipulation;-webkit-tap-highlight-color:transparent}
.rg-hero h1{margin:0;font-size:clamp(40px,7.5vw,68px);line-height:1.05;letter-spacing:-.02em;font-weight:800}
/* The label sits in flow so the eye centers on the full name+label block.
   Its left inset nudges the uppercase label's ink under the h1's 'R' (Hanken
   800 'R' bears 4.28px at 68px — ~.059x its clamp(40px,7.5vw,68px)). Kept
   from the Fragment-Mono tuning when the label went Hanken 600 (2026-07-13);
   reads aligned, re-measure the 'W' bearing if pixel-peeping. */
.rg-hero-name .rg-label{display:block;margin:2px 0 0 clamp(2.4px,.44vw,4px);font-size:clamp(11px,1.4vw,13px)}
.rg-tagline{margin:30px 0 0;font-size:clamp(20px,2.6vw,26px);line-height:1.4;font-weight:600;text-wrap:balance;color:var(--rg-accent-copy);transition:color .25s}
.rg-subhead{margin:18px 0 0;max-width:56ch;font-size:16px;line-height:1.7;color:var(--rg-dim)}
.rg-cta-row{margin-top:28px;display:flex;gap:18px;align-items:center;flex-wrap:wrap}

/* Primary CTA — rendered as a <span> while the Play listing URL doesn't
   exist ([PLAY_APP_URL]); swap to <a href> at launch. Neutral cream until a
   theme is picked, then it carries the accent. */
/* On-accent ink is pure #000: the darkest seeds (Indigo/Berry/Violet) sit at
   4.76-4.96:1 against it — AA — where the warmer #14120F fell just under 4.5. */
.rg-cta-primary{display:inline-block;background:var(--rg-accent);color:#000;border-radius:999px;padding:13px 26px;font-weight:700;font-size:15px;transition:background .25s}
.rg-cta-primary[data-href-placeholder]{cursor:default}
.rg-cta-faq{font-size:14.5px;color:var(--rg-ink);text-decoration:none;border-bottom:1px solid var(--rg-faint);padding-bottom:2px}
.rg-pill{font-family:var(--rg-label-font);font-weight:var(--rg-label-weight);font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--rg-dim);border:1px solid var(--rg-line);padding:6px 11px;border-radius:999px;white-space:nowrap}

/* ---- section scaffolding ---- */
.rg-band{padding:68px 0 76px}
.rg-band-warm{background:linear-gradient(180deg,#1E1B17,var(--rg-panel) 35%,#141210);border-top:1px solid var(--rg-line);border-bottom:1px solid var(--rg-line)}
.rg-sechead{display:flex;align-items:baseline;gap:20px;margin-bottom:14px}
.rg-sechead h2{margin:0;font-size:clamp(24px,3.4vw,32px);font-weight:800;letter-spacing:-.01em}
.rg-dotaccent{color:var(--rg-accent);transition:color .25s}
.rg-sechead .rg-rule{flex:1;height:1px;background:linear-gradient(90deg,color-mix(in srgb,var(--rg-accent) 30%,transparent),transparent)}

/* ---- screens: the app itself, full strips in watch half-bezels ---- */
/* Framing "D" (2026-07-12 mock session): a watch-top half-bezel with the
   whole screen visible at once. Bezels end where their content ends — the
   four strips differ in height by design. Cell width is tuned so all four
   fit the wrap at desktop width — 4×(210 strip + 22 bezel) + 3×28 gaps =
   1012 = the wrap's content box; each strip carries its own full bezel.
   Below that width the strip becomes a CENTERED carousel with a FIXED
   bezel (Jonathan, 2026-07-12): a watch-top arc stays put mid-screen
   (.rg-shots-bezel — bottomless, its sides fade out, since the strips it
   frames differ in height) while the bare screenshots and their titles
   slide through it on scroll-snap centering. Neighbors fade to the sides
   (.rg-shot-aside, marked by the page script) and tapping one scrolls it
   to center. Native scroll-snap does the actual carouselling — without JS
   the strip still swipes, it just doesn't fade. */
/* border-top matters: without it the seam from the features band's #131110
   to this band's deeper black read as ~140px of awkward void (2026-07-12) —
   the line turns the tone change into a deliberate section boundary, the
   same treatment rg-band-warm already had. */
.rg-band-deep{background:#0F0D0B;border-top:1px solid var(--rg-line);border-bottom:1px solid var(--rg-line)}
/* Adjacent deep bands (screens + tiles since the 2026-07-13 split) share
   ONE hairline at the seam, not a doubled border. */
.rg-band-deep+.rg-band-deep{border-top:0}
.rg-screens-lead{margin:14px 0 0;max-width:56ch;font-size:15px;line-height:1.7;color:var(--rg-dim)}
/* The stage carries the full-bleed margins so the strip's centering padding
   (% of the containing block) and the fixed arc's left:50% resolve against
   the SAME box — with the margins on the strip instead, the two centers
   diverge by the wrap padding and the arc sits 24px off the snapped cell. */
.rg-shots-stage{--shotw:min(210px,64vw);position:relative;margin:20px -24px 0}
.rg-shots{display:flex;gap:28px;align-items:flex-start;padding:6px 24px 18px;overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none}
.rg-shots::-webkit-scrollbar{display:none}
.rg-shots:focus-visible{outline:2px solid var(--rg-accent);outline-offset:-2px;border-radius:8px}
/* No captions on the cells (dropped 2026-07-12 — each strip's own first
   line IS its title, so labels above the bezels read twice). */
.rg-shot{margin:0;flex:0 0 auto;scroll-snap-align:start;transition:opacity .35s}
.rg-shot.rg-shot-aside,.rg-tile.rg-shot-aside{opacity:.35;cursor:pointer}
/* The strips open with ~48px of black padding and a centered title, so the
   semicircular top radius only ever clips empty background, never content. */
/* position:relative — the theme-swap ghosts (below) anchor to the frame. */
.rg-shot-frame{position:relative}
.rg-shot-frame img{display:block;width:var(--shotw);height:auto;border-radius:calc(var(--shotw)/2) calc(var(--shotw)/2) 20px 20px;background:#000}
/* Theme-swap crossfade (the page script's swapThemed): a clone of each
   OLD screenshot sits on top while the new theme loads beneath, then fades
   out — old pixels dissolve into new, and the bezels never animate.
   Deliberately not a view transition (Safari drops the mask-composite
   rings from its snapshots — blinking bezels on iPhone, 2026-07-13) and
   not an opacity dip on the imgs themselves (out-to-black + dark hold
   read as a blink, not a fade — iPhone again, same day). Sized by the
   same .rg-shot-frame img / .rg-tile img rules as the real imgs; this
   selector out-specifies them for the overlay bits. NO z-index: the cells
   aren't stacking contexts (position:relative + z-index:auto), so any
   z-index here escapes to the STAGE's context and paints the ghost over
   the fixed carousel bezel mid-scroll — appended-last DOM order already
   stacks it above its own img. */
.rg-shot-frame img.rg-swap-ghost,.rg-tile img.rg-swap-ghost,.rg-face-450 img.rg-swap-ghost{position:absolute;pointer-events:none;transition:opacity .35s}
/* Desktop: every strip wears its own full bezel; no fixed overlay. */
@media(min-width:1060px){
  .rg-shot-frame{padding:11px;background:var(--rg-bezel);border-radius:calc(var(--shotw)/2 + 11px) calc(var(--shotw)/2 + 11px) 30px 30px;box-shadow:0 30px 60px -30px rgba(0,0,0,.85),var(--rg-bezel-sheen)}
}
/* The fixed arc: an 11px ring (padding + mask-composite cut-out) over the
   centered strip, open at the bottom, its sides fading out. top = the
   strip's 6px padding-top minus the ring's 11px (the caption row that used
   to sit above the strips was cut 2026-07-12 as redundant). pointer-events
   off so taps land on the cells sliding beneath it. Base rule must stay
   ABOVE the carousel media block: its display:none loses to the block's
   display:block only by source order (equal specificity). */
.rg-shots-bezel{display:none;position:absolute;top:-5px;left:50%;transform:translateX(-50%);width:calc(var(--shotw) + 22px);height:calc(var(--shotw)/2 + 71px);pointer-events:none;-webkit-mask-image:linear-gradient(180deg,#000 62%,transparent 96%);mask-image:linear-gradient(180deg,#000 62%,transparent 96%)}
.rg-shots-bezel::before{content:"";position:absolute;inset:0;box-sizing:border-box;padding:11px;background:var(--rg-bezel);border-radius:calc(var(--shotw)/2 + 11px) calc(var(--shotw)/2 + 11px) 0 0;-webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);-webkit-mask-composite:xor;mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);mask-composite:exclude}
/* Carousel mode: bare strips (the fixed arc is the only bezel), padded so
   the FIRST and LAST cells can reach dead center. */
@media(max-width:1059px){
  .rg-shots{padding-left:calc(50% - var(--shotw)/2);padding-right:calc(50% - var(--shotw)/2)}
  .rg-shot{scroll-snap-align:center}
  .rg-shots-bezel{display:block}
}

/* ---- tiles strip: the nine round tiles below the screens (2026-07-12
   plan's second half). Same two-mode UX as the screens (Jonathan,
   2026-07-12): desktop is an even shelf, each cell wearing its own slim
   11px round bezel (same material as the strips' half-bezels); below the
   screens' 1060px breakpoint the cells go bare and slide through ONE fixed
   round bezel — a full ring, not the screens' bottomless arc, since uniform
   circles have a bottom to close — with the same centering padding,
   fade-aside and tap-to-center. Each tile's curved title (the Wear
   tile-picker look) floats just ABOVE its ring, not on a fattened band —
   the fat-band variant shipped briefly on 2026-07-12 and Jonathan bounced
   it same-day ("the bezel we had before was perfect"). Titles slide with
   their cells; --tpad reserves strip headroom for them, and the title
   canvas is the tile img's own box — geometry and the why (the vertical
   scroll bug) on .rg-tile-title below. */
.rg-tiles-lead{margin:14px 0 0;max-width:56ch;font-size:15px;line-height:1.7;color:var(--rg-dim)}
/* The stage carries the full-bleed margins for the same reason .rg-shots-stage
   does: the strip's centering padding and the fixed ring's left:50% must
   resolve against the SAME box. */
.rg-tiles-stage{--tilew:min(158px,44vw);--tpad:calc(8px + var(--tilew)/9);position:relative;margin:16px -24px 0}
.rg-tiles{display:flex;gap:22px;padding:var(--tpad) 24px 18px;overflow-x:auto;scroll-snap-type:x proximity;scrollbar-width:none}
.rg-tiles::-webkit-scrollbar{display:none}
.rg-tiles:focus-visible{outline:2px solid var(--rg-accent);outline-offset:-2px;border-radius:8px}
.rg-tile{position:relative;margin:0;flex:0 0 auto;scroll-snap-align:start;scroll-margin-left:24px;transition:opacity .35s}
.rg-tile img{display:block;width:var(--tilew);height:var(--tilew);border-radius:50%;background:#000}
/* The curved title, arcing just outside the ring's top. The svg BOX is the
   tile img's box exactly (inset 0; 11px under the desktop bezel padding) —
   an earlier 4/3-of-tile box overflowed the figures inside the overflow-x
   scroller and made the whole strip scroll VERTICALLY by the overhang
   (Jonathan, 2026-07-12). The arc paints outside the box via
   overflow:visible instead: painted overflow doesn't scroll, and the
   scroller clips paint at its own padding box, which --tpad keeps clear of
   the glyphs. viewBox units now map to the tile (240 = tilew), so the arc
   r=143 lands a few px outside the 11px ring at both cell sizes and 17px
   here ≈ 11.2px on a desktop cell. */
.rg-tile-title{position:absolute;inset:0;width:100%;height:100%;overflow:visible;pointer-events:none}
/* The explicit width/height above (and their calc() twins in the desktop
   block) are LOAD-BEARING: Safari does not stretch an absolutely
   positioned SVG to its inset box. With width/height auto it sizes the
   svg to 100% of the containing block, anchors it at the top/left insets,
   and ignores bottom/right (Chromium stretches to the inset box instead).
   Under the desktop inset:11px that painted this 240-unit viewBox onto a
   180px box instead of 158px — the whole title arc drew 14% too large
   with its center displaced +11px right/down, which reads as the titles
   "leaning" (the 2026-07-13 saga: four glyph-placement fixes chased the
   text; the glyphs were never askew — see the TILES comment). */
.rg-tile-title text{font-family:var(--rg-label-font);font-weight:var(--rg-label-weight);font-size:17px;letter-spacing:2.6px;text-transform:uppercase;text-anchor:middle;fill:var(--rg-ink)}
/* Desktop: every tile wears its own slim bezel; no fixed overlay. The
   stage also bleeds RIGHT to the viewport edge (Jonathan, 2026-07-13: the
   shelf used to cut at the wrap's right edge with dead margin beyond — on
   a wide screen the scroller should run to the screen edge). The wrap is
   1060px max with 24px side padding, so the extra right bleed past the
   base -24px margin is (100vw − 1060px)/2 → margin-right 506px − 50vw;
   the strip's right padding grows by the same amount so the last tile can
   still scroll fully into the wrap's content area. Left edge stays
   wrap-aligned with the section copy. The carousel JS is unaffected: the
   stage carries the margins (its documented contract) and cell offsets
   still resolve against the strip that fills it. */
@media(min-width:1060px){
  .rg-tile{padding:var(--rg-bezel-pad);background:var(--rg-bezel);border-radius:50%;box-shadow:0 22px 44px -24px rgba(0,0,0,.85),var(--rg-bezel-sheen)}
  .rg-tile-title{inset:var(--rg-bezel-pad);width:calc(100% - 2*var(--rg-bezel-pad));height:calc(100% - 2*var(--rg-bezel-pad))}
  .rg-tiles-stage{margin-right:calc(506px - 50vw)}
  .rg-tiles{padding-right:calc(50vw - 482px)}
}
/* Belt for the bleed above: with classic (non-overlay) scrollbars 100vw is
   wider than the layout viewport, so the stage's right edge could poke a
   few px past it — clip rather than grow a page-level horizontal scroll. */
body{overflow-x:clip}
/* The fixed ring: an 11px ring (padding + mask-composite cut-out, the
   .rg-shots-bezel::before construction closed into a full circle) around
   the centered tile — top = the strip's headroom padding minus the ring's
   11px. pointer-events off so taps land on the cells sliding beneath it.
   Base rule must stay ABOVE the carousel media block: its display:none
   loses to the block's display:block only by source order (equal
   specificity). */
.rg-tiles-bezel{display:none;position:absolute;top:calc(var(--tpad) - var(--rg-bezel-pad));left:50%;transform:translateX(-50%);width:calc(var(--tilew) + 2*var(--rg-bezel-pad));height:calc(var(--tilew) + 2*var(--rg-bezel-pad));pointer-events:none}
.rg-tiles-bezel::before{content:"";position:absolute;inset:0;box-sizing:border-box;padding:var(--rg-bezel-pad);background:var(--rg-bezel);border-radius:50%;-webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);-webkit-mask-composite:xor;mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);mask-composite:exclude}
/* Carousel mode: bare cells (the fixed ring is the only bezel), padded so
   the FIRST and LAST cells can reach dead center; mandatory snap like the
   screens, so the centered tile always lands inside the ring. The extra
   --tpad headroom clears the taller floating titles (the ring sits 11px
   proud of the cells, and the title arcs above that). */
@media(max-width:1059px){
  .rg-tiles-stage{--tilew:min(210px,64vw);--tpad:calc(10px + var(--tilew)/6)}
  .rg-tiles{scroll-snap-type:x mandatory;padding-left:calc(50% - var(--tilew)/2);padding-right:calc(50% - var(--tilew)/2)}
  .rg-tile{scroll-snap-align:center;scroll-margin-left:0}
  .rg-tiles-bezel{display:block}
}

/* ---- feature cards: no icons, type does the work ---- */
.rg-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(290px,1fr));gap:16px;margin-top:26px}
.rg-card{background:var(--rg-panel);border:1px solid var(--rg-line);border-radius:14px;padding:22px 22px 24px;transition:border-color .18s}
.rg-card:hover{border-color:rgba(236,231,219,.3)}
/* Card titles carry the accent (replacing the removed kickers as the cards'
   theme-reactive element); shares --rg-accent-copy with the tagline. */
.rg-card h3{margin:0;font-size:16.5px;font-weight:700;color:var(--rg-accent-copy);transition:color .25s}
.rg-card p{margin:8px 0 0;font-size:13.5px;line-height:1.65;color:var(--rg-dim)}

/* ---- theme swatches (compact since 2026-07-12 — demoted from their own
   band; sit between the section lead and the strips: one quiet invitation
   line, and a pick retints the page AND swaps the strips below to that
   theme's render set) ---- */
.rg-screens-colors{margin-top:18px}
.rg-swatch-hint{margin:30px 0 4px;font-family:var(--rg-label-font);font-weight:var(--rg-label-weight);font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--rg-dim)}
/* One line, ALWAYS (Jonathan, 2026-07-13 — a wrapped row orphaned Citron
   under the other five on phones and read as a layout accident). Instead
   of wrapping, the row compresses: the button PADDING gives first (it,
   not the dots, is what overflowed a 390px phone), then the dots and
   labels shrink on truly narrow screens. All three clamps hit their max
   at ≥~700px, so desktop/tablet render exactly as before; the floors are
   sized so even a 280px fold cover display fits without overflow. NB: do
   NOT "fix" a future overflow with overflow-x:auto here — a scroll
   container's paint clip would crop the pressed swatch's glow. */
.rg-swatches{--swpad:clamp(3px,1.5vw,10px);display:flex;gap:2px;margin-left:calc(var(--swpad)*-1)}
.rg-swatch{appearance:none;background:none;border:0;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:9px;padding:10px var(--swpad);font-family:var(--rg-label-font);font-weight:var(--rg-label-weight);font-size:clamp(7px,2.6vw,10px);letter-spacing:.14em;text-transform:uppercase;color:var(--rg-dim)}
.rg-swatch .rg-dot{width:clamp(26px,9vw,40px);height:clamp(26px,9vw,40px);border-radius:50%;background:var(--dot);box-shadow:0 0 0 1px rgba(236,231,219,.22);transition:box-shadow .15s,transform .15s}
.rg-swatch:hover .rg-dot{transform:scale(1.09)}
.rg-swatch[aria-pressed="true"]{color:var(--rg-ink)}
.rg-swatch[aria-pressed="true"] .rg-dot{box-shadow:0 0 0 2px var(--rg-panel),0 0 0 4px var(--dot),0 0 20px var(--dot)}

/* The .rg-placeholder asset-gap rules left with the face widgets
   (2026-07-13) — the faces were the page's last "Preview pending" dials,
   and the spec now asserts zero placeholders exist. Recover the rules from
   git history if a future section ships before its renders do. */

/* ---- watch faces ---- */
.rg-faces-lead{margin:22px 0 28px;max-width:60ch;font-size:15.5px;line-height:1.7}
.rg-face-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:16px;max-width:740px}
.rg-face-card{background:var(--rg-panel);border:1px solid var(--rg-line);border-radius:14px;padding:26px 24px;scroll-margin-top:80px}
.rg-face-card h3{margin:20px 0 0;font-size:19px;font-weight:800;letter-spacing:.01em}
.rg-face-card p{margin:9px 0 0;font-size:13.5px;line-height:1.65;color:var(--rg-dim)}
.rg-face-meta{margin-top:18px;display:flex;gap:10px;align-items:center;flex-wrap:wrap}
.rg-pill-free{background:var(--rg-accent);color:#000;border:0;font-weight:400;transition:background .25s}

/* ---- face preview widgets (2026-07-13) ----
   Each dial is the face's own 450px XML coordinate space, JS-scaled to fit
   its card (transform on .rg-face-450, set from the scaler's width — the
   night-preview harness pattern). Every px value in this block is verbatim
   from face-night/face-glow res/raw/watchface.xml; the HTML comment over
   #faces maps which value came from where. Page font stands in for the
   watch's Roboto (the harness's recorded fidelity caveat). */
.rg-face-bezel{width:min(100%,246px);margin:0 auto;border-radius:50%;padding:11px;background:var(--rg-bezel);box-shadow:0 22px 44px -24px rgba(0,0,0,.85),var(--rg-bezel-sheen)}
.rg-face-scaler{position:relative;width:100%;aspect-ratio:1;border-radius:50%;overflow:hidden;background:#000}
.rg-face-450{position:absolute;top:0;left:0;width:450px;height:450px;transform-origin:top left}
.rg-face-450>*{position:absolute}
.rg-night-canvas{left:0;top:0;width:450px;height:450px}
/* Night chrome: date PartText x125 y132 size 24 #b38e8e93; time TimeText
   x25 y165 size 76 LIGHT #fff (Glow's is 88 — no band trade there). */
.rg-face-date{left:125px;top:132px;width:200px;height:34px;display:flex;align-items:center;justify-content:center;font-size:24px;line-height:1;font-weight:400;color:rgba(142,142,147,.7)}
.rg-face-time{left:25px;top:165px;width:400px;height:100px;display:flex;align-items:center;justify-content:center;font-size:76px;line-height:1;font-weight:200;color:#fff;font-variant-numeric:tabular-nums}
/* Ghost-tip hands (§5.5): the face's own committed PNGs, pivot = bottom
   center placed on the face center, hub cap 18px over the flat pivot ends. */
.rg-face-hand{transform-origin:50% 100%}
.rg-face-hand-hour{left:218px;top:95px;width:14px;height:130px}
.rg-face-hand-minute{left:219px;top:37px;width:12px;height:188px}
.rg-face-cap{left:216px;top:216px;width:18px;height:18px;border-radius:50%;background:#fff}
.rg-face-sim[data-mode="digital"] .rg-face-hand,.rg-face-sim[data-mode="digital"] .rg-face-cap{display:none}
.rg-face-sim[data-mode="analog"] .rg-face-time{display:none}
/* Controls: quiet mono chips in the page voice (site-owned labels, pinned in
   the spec); the pressed state carries the live accent like the swatches. */
.rg-face-controls{margin-top:16px;display:flex;flex-direction:column;gap:10px}
.rg-face-slider{width:100%;accent-color:var(--rg-accent);margin:0}
.rg-face-btnrow{display:flex;align-items:center;justify-content:space-between;gap:8px;flex-wrap:wrap}
.rg-face-toggle{display:flex;gap:4px}
.rg-face-btn{appearance:none;cursor:pointer;background:none;border:1px solid var(--rg-line);border-radius:999px;padding:6px 13px;font-family:var(--rg-label-font);font-weight:var(--rg-label-weight);font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--rg-dim);transition:color .15s,border-color .15s,background .15s}
.rg-face-btn:hover{color:var(--rg-ink)}
.rg-face-btn[aria-pressed="true"]{background:var(--rg-accent);border-color:var(--rg-accent);color:#000}
/* Glow: the face XML's RadialGradients + cosine alpha Transforms as CSS.
   Layer gradients are the XML's literal centers/radii/color stops; each
   keyframe pair is the Transform's cosine at t=0 / half-period, ease-in-out
   standing in for the cosine easing. Static opacities = the t=0 values, so
   reduced motion (animation:none) rests at the face's own anchor frame.
   The toggle crossfades layer GROUPS (divs, not imgs — the img-blink rule
   is about photos over dark, and this is additive light on black). */
.rg-glow-layers{left:0;top:0;width:450px;height:450px;opacity:0;transition:opacity .35s}
.rg-glow-layers>div{position:absolute;left:0;top:0;width:450px;height:450px}
.rg-glow-sim[data-state="restored"] .rg-glow-restored,.rg-glow-sim[data-state="normal"] .rg-glow-normal,.rg-glow-sim[data-state="stressful"] .rg-glow-stressful{opacity:1}
.rg-glow-rest-in{background:radial-gradient(243px at 225px 207px,rgba(106,173,220,.6),rgba(106,173,220,.18) 55%,rgba(106,173,220,0) 100%)}
.rg-glow-rest-out{opacity:.102;background:radial-gradient(414px at 225px 207px,rgba(106,173,220,.459),rgba(106,173,220,.161) 55%,rgba(106,173,220,0) 100%)}
.rg-glow-norm{background:radial-gradient(243px at 225px 207px,rgba(106,129,220,.6),rgba(106,129,220,.169) 55%,rgba(106,129,220,0) 100%)}
.rg-glow-stress-a{background:radial-gradient(153px at 198px 194px,rgba(220,106,167,.878),rgba(220,106,167,.2) 55%,rgba(220,106,167,0) 100%)}
.rg-glow-stress-b{opacity:.51;background:radial-gradient(198px at 252px 221px,rgba(220,106,167,.722),rgba(220,106,167,.169) 55%,rgba(220,106,167,0) 100%)}
/* Animations only on the ACTIVE state's layers (review, 2026-07-13): the
   inactive groups sit at opacity:0 and must not keep the compositor busy —
   before this the five gradient layers all ticked forever from page load.
   A side benefit: each state re-enters at its t=0 anchor frame. */
.rg-glow-sim[data-state="restored"] .rg-glow-rest-in{animation:rgGlowRestIn 10s ease-in-out infinite}
.rg-glow-sim[data-state="restored"] .rg-glow-rest-out{animation:rgGlowRestOut 10s ease-in-out infinite}
.rg-glow-sim[data-state="normal"] .rg-glow-norm{animation:rgGlowNorm 7.5s ease-in-out infinite}
.rg-glow-sim[data-state="stressful"] .rg-glow-stress-a{animation:rgGlowStressA 5s ease-in-out infinite}
.rg-glow-sim[data-state="stressful"] .rg-glow-stress-b{animation:rgGlowStressB 6s ease-in-out infinite}
/* Glow's dauphine hands (its own hand_*.png — wider boxes than Night's:
   hour x216 w18, minute x218 w14) hold the face's 10:09 preview time; Glow
   has no time scrubbing, so the rotation is static CSS. */
.rg-glow-sim .rg-face-hand-hour{left:216px;width:18px;transform:rotate(304.5deg)}
.rg-glow-sim .rg-face-hand-minute{left:218px;width:14px;transform:rotate(54deg)}
/* Paused (stressed) or breathing at low amplitude (restored — the word
   breathes with the glow): the XML's word treatment per state. */
.rg-glow-time{font-size:88px}
.rg-glow-word{left:125px;top:268px;width:200px;height:22px;display:flex;align-items:center;justify-content:center;font-size:15px;line-height:1;font-weight:500;transition:color .35s}
.rg-glow-sim[data-state="restored"] .rg-glow-word{color:rgba(106,173,220,.8);animation:rgGlowWordRest 10s ease-in-out infinite}
.rg-glow-sim[data-state="normal"] .rg-glow-word{color:rgba(106,129,220,.8)}
.rg-glow-sim[data-state="stressful"] .rg-glow-word{color:rgba(220,106,167,.8)}
/* The 6-o'clock slot (x178 y322, 94px): Glow's one real swappable
   complication, wearing its real default — the readiness score. */
.rg-glow-comp{left:178px;top:322px;width:94px;height:94px}
.rg-glow-comp::before{content:"";position:absolute;inset:1px;border-radius:50%;border:1.5px solid rgba(58,58,64,.2)}
.rg-glow-comp svg{position:absolute;left:38px;top:14px;width:18px;height:18px;opacity:.9}
.rg-glow-comp span{position:absolute;left:7px;top:36px;width:80px;height:34px;display:flex;align-items:center;justify-content:center;font-size:26px;line-height:1;color:#f2f2f7}
@keyframes rgGlowRestIn{0%,100%{opacity:1}50%{opacity:.18}}
@keyframes rgGlowRestOut{0%,100%{opacity:.102}50%{opacity:1}}
@keyframes rgGlowNorm{0%,100%{opacity:1}50%{opacity:.851}}
@keyframes rgGlowWordRest{0%,100%{opacity:1}50%{opacity:.55}}
@keyframes rgGlowStressA{0%,100%{opacity:1}50%{opacity:.55}}
@keyframes rgGlowStressB{0%,100%{opacity:.51}50%{opacity:.95}}

/* ---- CTA band ---- */
.rg-get{text-align:center}
.rg-get .rg-label{display:block}
.rg-need{margin:16px auto 0;max-width:58ch;font-size:16px;line-height:1.7}
.rg-get .rg-cta-row{justify-content:center}

/* ---- fine print + footer ---- */
.rg-fineprint{padding:40px 0 48px;text-align:center}
.rg-fineprint p{margin:6px auto;max-width:74ch;font-size:12px;line-height:1.8;color:var(--rg-faint)}
.rg-fineprint a{color:var(--rg-dim)}
footer.rg-footer{border-top:1px solid var(--rg-line);padding:34px 0 44px}
footer.rg-footer .rg-wrap{display:flex;flex-wrap:wrap;gap:14px 26px;align-items:center;justify-content:space-between}
footer.rg-footer a{font-size:13px;color:var(--rg-dim);text-decoration:none;border-bottom:1px solid var(--rg-line);padding-bottom:2px}
footer.rg-footer .rg-copy{font-family:var(--rg-label-font);font-weight:var(--rg-label-weight);font-size:11px;letter-spacing:.06em;color:var(--rg-faint)}
/* Nakhla imprint: inline wordmark tints toward the picked accent (cream = neutral at load) */
footer.rg-footer a.rg-nakhla{border-bottom:0;padding-bottom:0;color:color-mix(in srgb,var(--rg-accent) 45%,var(--rg-dim))}
footer.rg-footer a.rg-nakhla svg{display:block;height:16px;width:auto}
footer.rg-footer a.rg-nakhla:hover{color:color-mix(in srgb,var(--rg-accent) 70%,var(--rg-ink))}

/* ---- FAQ + privacy prose pages ---- */
.rg-prose-head{padding:64px 0 6px}
.rg-prose-head h1{margin:14px 0 0;font-size:clamp(26px,3.8vw,36px);font-weight:800;letter-spacing:-.01em}
.rg-back{display:inline-block;font-family:var(--rg-label-font);font-weight:var(--rg-label-weight);font-size:12.5px;letter-spacing:.18em;text-transform:uppercase;text-decoration:none;color:var(--rg-dim);padding:8px 10px;margin-left:-10px}
.rg-back:hover{color:var(--rg-ink)}
.rg-prose{padding:12px 0 88px}
.rg-prose .rg-wrap,.rg-prose-head .rg-wrap{max-width:760px}
.rg-faq-item{padding:28px 0;border-bottom:1px solid var(--rg-line)}
.rg-faq-item:first-child{padding-top:14px}
.rg-faq-item:last-of-type{border-bottom:0}
.rg-faq-item h2{margin:0;font-size:18px;font-weight:700}
.rg-faq-outro{margin:30px 0 0;font-size:14.5px;line-height:1.75;color:var(--rg-dim)}
.rg-faq-item p{margin:12px 0 0;font-size:14.5px;line-height:1.75;color:var(--rg-dim)}
.rg-prose a{color:var(--rg-ink)}
.rg-prose h2{margin:42px 0 0;font-size:19px;font-weight:700}
.rg-prose .rg-faq-item h2{margin:0;font-size:18px}
.rg-prose h1+p,.rg-prose h2+p,.rg-prose h2+ul{margin-top:14px}
.rg-prose p,.rg-prose li{font-size:14.5px;line-height:1.75;color:var(--rg-dim)}
.rg-prose ul{margin:12px 0 0;padding-left:22px}
.rg-prose li{margin:7px 0}
.rg-prose strong{color:var(--rg-ink);font-weight:700}
.rg-meta-block{margin:22px 0 0;padding:16px 20px;border-left:2px solid var(--rg-accent);background:rgba(236,231,219,.04);font-family:var(--rg-label-font);font-weight:var(--rg-label-weight);font-size:12.5px;line-height:1.9;color:var(--rg-dim)}

@media(max-width:700px){
  .rg-hero{padding:56px 0 52px}
  .rg-band{padding:52px 0 58px}
  .rg-prose-head{padding:48px 0 2px}
}
@media (prefers-reduced-motion:reduce){
  .rg-eye,.rg-eye .rg-pupil,.rg-swatch .rg-dot,.rg-swatch:hover .rg-dot,.rg-cta-primary,.rg-card,.rg-tagline,.rg-card h3,.rg-dotaccent,.rg-label,.rg-pill-free,.rg-shot,.rg-tile{transition:none;transform:none}
  /* Ghosts never exist under reduced motion (the JS takes the instant
     path), but if one ever did, this must out-specify the ghost rule's
     (0,2,1) or the reset loses — the lockup lesson below. */
  .rg-shot-frame img.rg-swap-ghost,.rg-tile img.rg-swap-ghost,.rg-face-450 img.rg-swap-ghost{transition:none}
  /* Face widgets: freeze the glow at its anchor frame (static opacities are
     the XML Transforms' t=0 values) and swap states/toggles instantly.
     [data-state] bumps specificity above the state-scoped animation rules
     (0,3,0) — the lockup lesson: a weaker reset silently loses. */
  .rg-glow-layers,.rg-glow-word,.rg-face-btn{transition:none}
  .rg-glow-sim[data-state] .rg-glow-layers>div,.rg-glow-sim[data-state="restored"] .rg-glow-word{animation:none}
  .rg-header .rg-lockup{transition:none}
  /* Must repeat the hidden state at its own (0,3,0) specificity: the base
     .rg-lockup-hidden rule re-specifies transition, so a (0,2,0) reset loses
     to it and the hide would still fade. */
  .rg-header .rg-lockup.rg-lockup-hidden{transform:none;transition:none}
}
