/* CoreBuild — shared stylesheet.
   Extracted from index.html on 2026-08-12 when the single page became a
   multi-page site. Every page links this file; nothing is page-specific here.
   Design-system notes and the CSS traps live in HANDOVER.md — read them before editing. */

/* ============================================================
   CoreBuild — the official company website. This file is the HOME page;
   further pages are being built before launch. (It began life as a
   standalone one-page sales sheet, which is why everything still lives
   in one file.)

   TYPE SYSTEM (deliberate, not decorative):
     Zen Old Mincho    → emotional/brand statements only
     Zen Kaku Gothic   → every factual, operational, numeric thing
   The split IS the voice: feeling is set in mincho, facts in gothic.
   Google Fonts with a full JP system fallback chain, so an offline
   client meeting degrades to Hiragino/Yu rather than to nothing.

   COLOR: Committed dark. ONE luminous jade (#0FCB88) carries the
   brand. LINE's own green (#06C755) is reserved EXCLUSIVELY for
   literal LINE elements — using LINE's trademark colour as our
   identity would read as "LINE's product", not ours. Brass is the
   money/receipt hue. Text/BG pairs verified ≥4.5:1.

   MOTION: varied per section, never one uniform entrance —
   mask-wipe (hero), stagger (lists), line-draw (timeline),
   scale-in (product), count-up (figures). Reveals ENHANCE an
   already-visible default: content is visible without JS, the
   `.js` class opts into hiding, so a headless render never ships
   blank. prefers-reduced-motion ⇒ crossfade, all loops off.

   PERF: no full-viewport backdrop-filter and no blend-mode grain
   (both stutter on the mid-range phones our buyers actually use).
   Glass is expensive, so it is spent only where it means something:
   the header, the product device, the price panel.

   Hooks kept: ?static (no reveal gating — print/capture/old
   tablets), ?only=<id> (render one section alone).
   ============================================================ */
*, *::before, *::after { margin:0; padding:0; box-sizing:border-box; }

:root {
  /* surface ramp */
  --bg:#07080b;
  --bg-2:#0b0d12;
  --hair:rgba(255,255,255,.11);
  --hair-2:rgba(255,255,255,.18);
  /* ink ramp — all verified on --bg */
  --ink:#f2f4f5;          /* 17.8:1 */
  --sub:#a9b1bb;          /*  8.7:1 */
  --faint:#79818c;        /*  4.6:1 — large/secondary only */
  /* brand */
  /* BRAND — matches the dashboard's accent, so the two products read as one
     family (Guto, 2026-08-27). 6.4:1 on --bg. */
  --amber:#FF5A1F;
  --amber-dim:#E04A15;    /* 4.9:1 — hairlines, hover, dimmed states */
  --amber-ink:#1c0800;    /* 6.2:1 — ink used ON amber surfaces */
  /* MEANING, not brand: jade now says one thing only — automated, included,
     working. It is never spent on decoration, or the 自動化 badge stops
     being information and becomes styling. */
  --jade:#0FCB88;         /* 10.4:1 on --bg */
  --jade-dim:#0a9a67;
  --jade-ink:#04211a;     /* ink used ON jade surfaces */
  --brass:#d8a94b;        /* money / receipts */
  /* the green family, 2026-08-20. Each one owns a ROLE — they are not
     decoration, and nothing may use them as a spare accent:
       teal   = structure and reference: the things people file, not automate
       spring = live / happening now
       mint   = a quiet second voice next to jade
       sea    = distance; the far layer of the sky recedes with it
     Picked from the palette Guto supplied, then adjusted so each clears
     contrast on --bg rather than shipping the raw CSS named colour. */
  --teal:#1FB2A6;
  --spring:#4BF0A5;
  --mint:#79D8B4;
  --sea:#2E8B57;
  --line:#06C755;         /* LINE brand — LINE elements ONLY */
  /* type */
  --mincho:"Zen Old Mincho","Hiragino Mincho ProN","Yu Mincho","YuMincho",serif;
  --goth:"Zen Kaku Gothic New","Hiragino Sans","Hiragino Kaku Gothic ProN","Yu Gothic",sans-serif;
  /* motion */
  --eo:cubic-bezier(0.16,1,0.3,1);          /* ease-out-expo-ish */
  --eo2:cubic-bezier(0.22,0.61,0.36,1);
  /* z-scale — semantic, never arbitrary */
  --z-sky:0; --z-content:1; --z-drench:2; --z-header:40; --z-prog:50;
}

html { background:var(--bg); scroll-behavior:smooth; }
/* overflow-x:CLIP not hidden — `hidden` on body silently promotes body to
   the scroll container, which breaks fixed-layer compositing in some
   renderers (blank snapshots). `clip` clips without creating a scroller. */
html, body { overflow-x:clip; }
body {
  font-family:var(--goth); font-weight:400; color:var(--ink);
  font-feature-settings:"palt"; -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  background:
    radial-gradient(120vw 92vh at 84% -12%, #0f1720 0%, transparent 58%),
    radial-gradient(88vw 78vh at -12% 108%, #0b1014 0%, transparent 52%),
    var(--bg);
}

::selection { background:var(--amber); color:var(--amber-ink); }

/* keyboard access — never remove focus without replacement */
:focus-visible {
  outline:2px solid var(--amber); outline-offset:3px; border-radius:4px;
}
.skip {
  position:absolute; left:-9999px; top:0; z-index:99;
  background:var(--amber); color:var(--amber-ink);
  padding:14px 22px; font-weight:700; border-radius:0 0 12px 0;
}
.skip:focus { left:0; }

/* ---------- header ---------- */
.hd {
  position:fixed; inset:0 0 auto 0; z-index:var(--z-header);
  display:flex; align-items:center; justify-content:space-between;
  gap:20px; padding:16px clamp(20px,7vw,88px);
  /* background/border only — animating padding would reflow the bar on
     every scroll frame. The material change alone reads as "stuck". */
  transition:background .5s var(--eo), border-color .5s var(--eo);
  border-bottom:1px solid transparent;
}
.hd.stuck {
  background:rgba(9,11,15,.72);
  -webkit-backdrop-filter:blur(18px) saturate(1.4); backdrop-filter:blur(18px) saturate(1.4);
  border-bottom-color:var(--hair);
}
/* Brand only in the header — the legal entity lives in the closing section
   and the footer, not up here. Vertical padding takes the hit area to 44px+;
   it measured 105x27.5 when the entity name sat alongside. */
.mark { display:inline-flex; align-items:center; padding:9px 0; min-height:44px;
  text-decoration:none; color:var(--ink); }
.mark { gap:11px; }
.mark .sym { width:clamp(28px,3vw,34px); height:auto; flex:none; }
.mark .n { font-family:var(--mincho); font-weight:700; font-size:25px; letter-spacing:.05em; }
/* two lockups, one switch: the site's Mincho wordmark by default, the
   generated one when <html data-logo="lockup"> is set. */
.mark .wm { display:none; height:clamp(17px,1.9vw,21px); width:auto; }
html[data-logo="lockup"] .mark .n { display:none; }
html[data-logo="lockup"] .mark .wm { display:block; }
/* THE FULL LOCKUP STAYS ON A PHONE (Guto, 2026-09-01: "have the full CoreBuild logo
   appear on the top left — I want it to be visible"). It used to drop to the symbol alone
   below 560px because the Mincho wordmark collided with the language toggle and wrapped to
   "CoreBuil / d". The generated wordmark is an image, so it cannot wrap — it only has to be
   made to fit, which is a matter of giving back the ~40px the 7vw side padding was taking
   and letting the type step down one notch. Measured at 320/360/375/390: no overflow. */
@media (max-width:700px){
  .hd { padding-inline:16px; gap:10px; }
  .mark { gap:8px; }
  .mark .sym { width:26px; }
  html[data-logo="lockup"] .mark .wm { display:block; height:15px; }
  .mark .n { display:none; }
  /* both controls belong to the same hand: the pair sits against the menu button rather
     than stranded in the middle of the bar, which is where space-between had put it */
  .hd .right { margin-left:auto; }
  .lang button { padding:7px 10px; font-size:11px; }
}
/* At 320 the three header items want 130 + 118 + 40 plus gaps against 296 of usable width,
   so every part gives a little rather than the logo giving everything. Measured, not guessed:
   the language pill is 118px wide, not the ~84 an estimate suggests. */
@media (max-width:360px){
  .hd { padding-inline:10px; gap:8px; }
  .mark { gap:6px; }
  .mark .sym { width:24px; }
  html[data-logo="lockup"] .mark .wm { height:12px; }
  .lang button { padding:5px 7px; font-size:10px; }
  .burger { width:40px; padding:0 9px; }
}
/* Below 300px there is genuinely no room for a wordmark beside two controls, and a clipped
   logo is worse than no logo. Narrower than any handset sold; this is the floor, not a case. */
@media (max-width:300px){
  html[data-logo="lockup"] .mark .wm { display:none; }
  .mark .sym { width:28px; }
}
.hd .go { font-size:13.5px; padding:11px 22px; }
.hd .right { display:flex; align-items:center; gap:14px; }

/* language switch */
/* flex:none and nowrap are load-bearing, not tidiness: as a shrinkable flex item this pill
   was squeezed below its content width at 320px and 「日本語」 wrapped to 日本 / 語 — a
   mid-word break in Japanese, which the site forbids everywhere else. The header's flexible
   item is the brand lockup, never a control with text in it. */
.lang { display:flex; align-items:center; padding:3px; border-radius:100px; flex:none;
  border:1px solid var(--hair-2); background:rgba(255,255,255,.04); }
.lang button { white-space:nowrap; }
.burger { flex:none; }
.mark { flex:none; }
.lang button {
  font:inherit; font-size:11.5px; font-weight:900; letter-spacing:.08em; cursor:pointer;
  padding:7px 13px; border:0; border-radius:100px; background:none; color:var(--faint);
  transition:color .3s var(--eo), background .3s var(--eo);
}
.lang button:hover { color:var(--ink); }
.lang button[aria-pressed="true"] { background:var(--ink); color:var(--bg); }

@media (max-width:640px){ .hd .go { display:none; } .mark .n { font-size:22px; } }

/* ---------- Japanese line breaking ----------
   Japanese must wrap at word/phrase boundaries, never mid-word:
     BAD  これらのサー / ビスを行って / ます。
     GOOD これらの / サービスを / 行ってます。
   auto-phrase is the modern answer but Safari doesn't ship it, and this
   page is reviewed on an iPhone — so JS segments the text and wraps each
   unit in an inline-block, which the browser cannot break inside.
   overflow-wrap is the safety net: a unit too long for its column
   degrades to a normal break instead of overflowing the layout. */
/* The injected units are new descendant spans, so any rule written as
   `.something span { border… }` would paint every unit as its own chip.
   Reset them, and scope such rules to `> span`. */
.u { display:inline-block; border:0; padding:0; margin:0; background:none; }
[lang="ja"] { word-break:auto-phrase; overflow-wrap:anywhere; }
/* English needs none of the JP typographic machinery */
html[data-lang="en"] body { font-feature-settings:normal; }
html[data-lang="en"] .disp { word-break:normal; }

/* ---------- scroll progress ---------- */
#prog { position:fixed; inset:0 0 auto 0; height:2px; z-index:var(--z-prog); pointer-events:none; }
#prog i {
  display:block; height:100%; background:var(--amber);
  transform:scaleX(0); transform-origin:0 50%;
}

/* ---------- the sky (fixed, alive on every screen) ---------- */
#sky { position:fixed; inset:0; z-index:var(--z-sky); pointer-events:none; overflow:hidden; }
.blob { position:absolute; border-radius:50%; will-change:transform; }
.blob.b1 { width:56vmax; height:56vmax; top:-24vmax; right:-16vmax;
  background:radial-gradient(circle, rgba(255,90,31,.11), transparent 62%);
  animation:blobA 38s ease-in-out infinite alternate; }
.blob.b2 { width:44vmax; height:44vmax; bottom:-18vmax; left:-14vmax;
  background:radial-gradient(circle, rgba(216,169,75,.055), transparent 60%);
  animation:blobB 47s ease-in-out infinite alternate; }
.blob.b3 { width:32vmax; height:32vmax; top:36%; left:54%;
  background:radial-gradient(circle, rgba(120,170,255,.045), transparent 58%);
  animation:blobC 33s ease-in-out infinite alternate; }
/* sparks: small points of light crossing the field, so the sky has
   fast movement against all the slow drifting mass */
.spark { position:absolute; width:3px; height:3px; border-radius:100px;
  background:var(--amber); opacity:0; will-change:transform,opacity; }
.spark.s1  { top:18%; left:-4%; animation:cross 14s linear infinite; }
.spark.s2  { top:62%; left:-4%; animation:cross 19s linear infinite 5s; }
.spark.s3  { top:38%; left:-4%; animation:cross 11s linear infinite 9s; background:var(--brass); }
.spark.s4  { top:80%; left:-4%; animation:cross 23s linear infinite 2s; }
.spark.s5  { top:8%;  left:-4%; animation:cross 16s linear infinite 7s; }
.spark.s6  { top:50%; left:-4%; animation:cross 9s  linear infinite 3s; width:2px; height:2px; }
.spark.s7  { top:28%; left:-4%; animation:cross 21s linear infinite 12s; background:var(--brass); }
.spark.s8  { top:71%; left:-4%; animation:cross 13s linear infinite 6s; width:4px; height:4px; }
/* a second current running the other way, so the field has cross-traffic */
.spark.u1 { bottom:-4%; left:16%; animation:rise 17s linear infinite 1s; }
.spark.u2 { bottom:-4%; left:44%; animation:rise 12s linear infinite 6s; width:2px; height:2px; }
.spark.u3 { bottom:-4%; left:68%; animation:rise 22s linear infinite 3s; background:var(--brass); }
.spark.u4 { bottom:-4%; left:88%; animation:rise 15s linear infinite 10s; }
@keyframes cross {
  0%   { transform:translate3d(0,0,0) scale(.6); opacity:0; }
  8%   { opacity:.85; }
  70%  { opacity:.6; }
  100% { transform:translate3d(112vw,-14vh,0) scale(1.3); opacity:0; }
}
@keyframes rise {
  0%   { transform:translate3d(0,0,0) scale(.5); opacity:0; }
  10%  { opacity:.8; }
  75%  { opacity:.5; }
  100% { transform:translate3d(-9vw,-108vh,0) scale(1.2); opacity:0; }
}
@keyframes blobA { from{transform:translate3d(0,0,0) scale(1)}     to{transform:translate3d(-8vmax,6vmax,0) scale(1.12)} }
@keyframes blobB { from{transform:translate3d(0,0,0) scale(1.06)}  to{transform:translate3d(7vmax,-5vmax,0) scale(.95)} }
@keyframes blobC { from{transform:translate3d(0,0,0)}              to{transform:translate3d(-6vmax,-8vmax,0) scale(1.18)} }

#sky .layer { position:absolute; inset:-14vh 0; will-change:transform; }
.orbits { position:absolute; inset:0; width:100%; height:100%; opacity:.45; }

/* Occasional energy links between two drifting objects. Injected into the same
   .layer as both endpoints so the parallax carries them for free — no per-frame
   rect reads. Both ends fade out, which is also why the small drift offset
   between a line end and its icon never reads as misalignment. */
.skylink { position:absolute; height:1px; transform-origin:0 50%;
  pointer-events:none; opacity:0; will-change:opacity;
  background:linear-gradient(90deg,
    transparent 0%, rgba(255,90,31,.17) 22%,
    rgba(255,90,31,.17) 78%, transparent 100%); }
.skylink.lit { opacity:1; transition:opacity .55s cubic-bezier(0.16,1,0.3,1); }
.skylink.out { opacity:0; transition:opacity .5s linear; }
.skypulse { position:absolute; top:50%; left:0; width:7px; height:7px;
  margin:-3.5px 0 0 -3.5px; border-radius:100px; background:#ffd9c6;
  box-shadow:0 0 7px 1px rgba(255,90,31,.6); opacity:0; }
.skylink.lit .skypulse { animation:skyrun var(--dur,1500ms) linear .18s 1 forwards; }
@keyframes skyrun {
  0%   { opacity:0; transform:translateX(0); }
  12%  { opacity:1; }
  88%  { opacity:1; }
  100% { opacity:0; transform:translateX(var(--len,200px)); }
}

@media (prefers-reduced-motion:reduce){ .skylink { display:none; } }
.obj { position:absolute; }
.obj svg { display:block; overflow:visible; }
/* Six distinct drift personalities. Objects travel further, rotate harder
   and breathe in scale, at deliberately unmatched durations so the field
   never falls into a visible common rhythm. */
.bob  { animation:driftA 13s ease-in-out infinite alternate; }
.bob2 { animation:driftB 17s ease-in-out infinite alternate-reverse; }
.bob3 { animation:driftC 21s ease-in-out infinite alternate; }
.bob4 { animation:driftD 15s ease-in-out infinite alternate-reverse; }
.bob5 { animation:driftE 26s linear infinite; }
.bob6 { animation:driftF 19s ease-in-out infinite alternate; }
@keyframes driftA {
  0%   { transform:translate3d(0,-16px,0) rotate(-7deg) scale(.94); }
  50%  { transform:translate3d(34px,14px,0) rotate(9deg) scale(1.09); }
  100% { transform:translate3d(-12px,26px,0) rotate(-4deg) scale(1); }
}
@keyframes driftB {
  0%   { transform:translate3d(0,18px,0) rotate(11deg) scale(1.06); }
  50%  { transform:translate3d(-38px,-10px,0) rotate(-8deg) scale(.9); }
  100% { transform:translate3d(16px,-28px,0) rotate(5deg) scale(1.04); }
}
@keyframes driftC {
  0%   { transform:translate3d(-20px,10px,0) rotate(-14deg) scale(1); }
  50%  { transform:translate3d(22px,-30px,0) rotate(6deg) scale(1.12); }
  100% { transform:translate3d(30px,20px,0) rotate(16deg) scale(.92); }
}
@keyframes driftD {
  0%   { transform:translate3d(12px,-22px,0) rotate(8deg) scale(1.08); }
  50%  { transform:translate3d(-26px,18px,0) rotate(-12deg) scale(.95); }
  100% { transform:translate3d(20px,30px,0) rotate(3deg) scale(1.05); }
}
/* a full slow tumble — the one object that never settles */
@keyframes driftE {
  0%   { transform:translate3d(0,0,0) rotate(0deg) scale(1); }
  25%  { transform:translate3d(40px,-24px,0) rotate(90deg) scale(1.1); }
  50%  { transform:translate3d(8px,36px,0) rotate(180deg) scale(.9); }
  75%  { transform:translate3d(-36px,-12px,0) rotate(270deg) scale(1.06); }
  100% { transform:translate3d(0,0,0) rotate(360deg) scale(1); }
}
@keyframes driftF {
  0%   { transform:translate3d(-28px,-14px,0) rotate(4deg) scale(.88); }
  50%  { transform:translate3d(30px,22px,0) rotate(-15deg) scale(1.14); }
  100% { transform:translate3d(-8px,-30px,0) rotate(10deg) scale(.96); }
}
/* Kept faint on purpose: these drift behind live copy, and anything
   heavier turns the reading column into a collision. */
.far  { opacity:.17; }
.mid  { opacity:.30; }
.near { opacity:.42; }
/* grain: plain low-opacity noise. No mix-blend-mode — blending a
   full-screen fixed layer re-composites on every scroll frame.
   width/height attrs are REQUIRED: an <svg> keeps its 300x150
   intrinsic size and `inset:0` alone leaves a noise patch in the
   corner instead of a full-bleed layer. */
#grain { position:fixed; inset:0; z-index:3; pointer-events:none; opacity:.03;
  width:100%; height:100%; }

/* ---------- section shell ---------- */
main { position:relative; z-index:var(--z-content); }
/* Only the hero and the two drenched statements get a full screen. Every
   other section is sized by its content: a landing page that takes 17
   screens to read is a landing page nobody finishes. */
section {
  position:relative; display:flex; flex-direction:column; justify-content:center;
  padding:clamp(64px,9vh,104px) clamp(20px,7vw,88px);
}
section.full { min-height:100svh; }
section.short { padding:0; }
.wrap { width:100%; max-width:1180px; margin:0 auto; }

/* Statement bands. NOT solid green slabs: a tinted, transparent field
   the drifting sky still shows through, edged with hairlines so it reads
   as a deliberate band rather than a painted block. */
section.drench {
  z-index:var(--z-drench); color:var(--ink); overflow:hidden;
  background:
    linear-gradient(152deg, rgba(255,90,31,.17) 0%, rgba(6,165,109,.05) 48%, rgba(255,90,31,.13) 100%);
  border-block:1px solid rgba(255,90,31,.26);
}
section.drench::after {
  content:""; position:absolute; inset:-40%; pointer-events:none;
  background:radial-gradient(40% 40% at 50% 50%, rgba(255,90,31,.16), transparent 64%);
  animation:sweep 19s ease-in-out infinite alternate;
}
section.drench .disp em { color:var(--amber); font-style:normal; }
@keyframes sweep { from{transform:translate3d(-18%,-12%,0)} to{transform:translate3d(20%,14%,0)} }
section.drench > * { position:relative; z-index:1; }

/* ---------- type ---------- */
/* mincho = feeling. gothic = fact. never mixed by accident. */
/* auto-phrase breaks Japanese at phrase boundaries instead of mid-compound
   (全部 split across two lines); ignored by browsers that lack it. */
.disp { font-family:var(--mincho); font-weight:600; letter-spacing:-.01em;
        line-height:1.34; text-wrap:balance; word-break:auto-phrase; }
/* min sized so 「あとは全部、自動。」 stays on ONE line at 375px */
.h-hero { font-size:clamp(35px,7.6vw,88px); line-height:1.26; }
/* The English headline is three long sentences where the Japanese is three
   short phrases, so at phone width it wraps to roughly twice the lines and
   pushed the CTA below the fold (898px of an 850px viewport, 2026-08-30).
   English gets its own step down; Japanese is untouched. */
html[data-lang="en"] .h-hero { font-size:clamp(28px,5.9vw,74px); line-height:1.22; }
@media (max-width:620px){
  html[data-lang="en"] .hero-sub { font-size:clamp(13px,3.4vw,15px); }
}
/* Mobile floors are set so the longest single JP phrase still fits the
   column. Too large and the phrase overflows, which forces the browser
   to break inside a word — the exact break we removed. */
.h-big  { font-size:clamp(27px,4.5vw,60px); }
/* factual headings stay gothic — the contrast is the system */
.h-fact { font-family:var(--goth); font-weight:900; letter-spacing:-.015em;
          font-size:clamp(24px,3.5vw,46px); line-height:1.4; text-wrap:balance; }
.lede { font-size:clamp(15.5px,1.45vw,20px); color:var(--sub); line-height:2.05;
        max-width:34em; text-wrap:pretty; }
.lede strong, .lede b { color:var(--ink); font-weight:900; }
.disp em { font-style:normal; color:var(--amber); }
.tnum { font-variant-numeric:tabular-nums; font-feature-settings:"tnum" 1; }
/* product names stay whole across a line break */
.nw { white-space:nowrap; }

/* ---------- reveals (varied per section, never one uniform entrance) --- */
/* default = visible. `.js` opts into hiding, so no-JS/headless ships full. */
.js .rv    { opacity:0; transform:translate3d(0,26px,0); }
.js .in .rv{ opacity:1; transform:none; transition:opacity .85s var(--eo), transform .85s var(--eo); }
.js .rv-l  { opacity:0; transform:translate3d(-22px,0,0); }
.js .in .rv-l { opacity:1; transform:none; transition:opacity .8s var(--eo), transform .8s var(--eo); }
.js .rv-s  { opacity:0; transform:scale(.955) translate3d(0,14px,0); }
.js .in .rv-s { opacity:1; transform:none; transition:opacity 1s var(--eo), transform 1.1s var(--eo); }
.js .in .d1{ transition-delay:.06s } .js .in .d2{ transition-delay:.12s }
.js .in .d3{ transition-delay:.18s } .js .in .d4{ transition-delay:.24s }
.js .in .d5{ transition-delay:.30s } .js .in .d6{ transition-delay:.36s }
/* hero line wipe */
.mask { display:block; overflow:hidden; padding-bottom:.06em; }
.mask > span { display:block; }
.js .mask > span { transform:translate3d(0,108%,0); }
.js .in .mask > span { transform:none; transition:transform 1.15s var(--eo); }
.js .in .mask.m2 > span { transition-delay:.11s; }
.js .in .mask.m3 > span { transition-delay:.22s; }


/* ═══ AUTHORED MOMENTS ════════════════════════════════════════════════════
   Three of them, added 2026-08-28. Deliberately few: an enterprise reads as
   precise, not busy, and Emil's frequency rule kills anything a visitor
   would see dozens of times. Each fires once, on arrival, and every one is
   transform/opacity or a single stroke — no layout animation. */

/* ── 1. headings assemble phrase by phrase ────────────────────────────────
   The site already segments Japanese into 文節 at runtime for line-breaking.
   Reusing those same units as the reveal beat is something only this site
   can do: the sentence arrives the way it is read, not letter by letter
   (kana-by-kana would be gibberish) and not all at once. English headings
   fall back to word units so the two languages behave alike. */
.js .ph-in .u,
.js .ph-in .w { opacity:0; transform:translate3d(0,10px,0); display:inline-block; }
.js .in .ph-in .u,
.js .in .ph-in .w {
  opacity:1; transform:none;
  transition:opacity .5s var(--eo), transform .62s var(--eo);
  transition-delay:calc(var(--i,0) * 46ms);      /* Emil: 30–80ms between items */
}

/* ── 2. the section rail — enterprise wayfinding ──────────────────────────
   A fixed index of the page's own sections. Numbers only, so it needs no
   translation and never disagrees with the copy. Desktop only: on a phone it
   would be chrome competing with the content it indexes. */
.rail-x { position:fixed; left:clamp(14px,2.2vw,30px); top:50%; translate:0 -50%;
  z-index:calc(var(--z-header) - 2); display:none; flex-direction:column;
  gap:14px; align-items:flex-start; pointer-events:auto; }
@media (min-width:1180px){ .js .rail-x { display:flex; } }
.rail-x a { display:flex; align-items:center; gap:9px; text-decoration:none;
  font-size:10.5px; font-weight:800; letter-spacing:.14em; color:var(--faint);
  transition:color .3s var(--eo); }
.rail-x i { display:block; width:30px; height:1px; background:currentColor;
  opacity:.5; transform:scaleX(.467); transform-origin:left center;
  transition:transform .34s var(--eo), opacity .34s var(--eo); }
@media (hover:hover){ .rail-x a:hover { color:var(--sub); } }
.rail-x a[aria-current="true"] { color:var(--amber); }
.rail-x a[aria-current="true"] i { transform:scaleX(1); opacity:1; }

/* ── 3. the wire charges when a folder opens ─────────────────────────────
   The lit wire draws itself from 御社 to the card, so opening a folder looks
   like something travelling into it rather than a colour switch. Reuses the
   diagram's own visual language (particles riding wires) with one stroke. */
.fx-wires path.lit { stroke-dasharray:var(--len,600); stroke-dashoffset:0;
  transition:stroke .35s var(--eo), opacity .35s var(--eo),
             stroke-dashoffset .62s var(--eo); }
.fx-wires path.lit.charge { stroke-dashoffset:var(--len,600); transition:none; }

@media (prefers-reduced-motion:reduce){
  /* the content still arrives — it just stops travelling to get here */
  .js .ph-in .u, .js .ph-in .w,
  .js .in .ph-in .u, .js .in .ph-in .w { opacity:1; transform:none; transition:none; }
  .rail-x a, .rail-x i { transition:none; }
  .fx-wires path.lit, .fx-wires path.lit.charge { transition:stroke .2s linear;
    stroke-dasharray:none; stroke-dashoffset:0; }
}


/* ── 4. cards arrive in sequence, not as a slab ───────────────────────────
   The moments above are desktop-weighted — the rail is hidden on a phone and
   hover does not exist there — and this site is reviewed on a phone first
   (PRODUCT.md). This one is built for that screen: every grid of cards deals
   itself out, one card 55ms after the last, so a section lands as a sequence
   instead of appearing whole. Transform and opacity only. */
.js .deal > * { opacity:0; transform:translate3d(0,18px,0); }
.js .in .deal > *,
.js .deal.in > * {
  opacity:1; transform:none;
  transition:opacity .55s var(--eo), transform .66s var(--eo);
  transition-delay:calc(var(--i,0) * 55ms);
}
/* ── 5. the map comes online ──────────────────────────────────────────────
   When the folder section arrives, the nine wires draw outward from 御社 one
   after another — the structure assembling itself rather than being present.
   Visible on a phone, which the wire-charge on open is not until you tap. */
.fx-wires path { stroke-dasharray:var(--len,600); stroke-dashoffset:0; }
.fx.boot .fx-wires path { stroke-dashoffset:var(--len,600); }
.fx.booted .fx-wires path { stroke-dashoffset:0;
  transition:stroke-dashoffset .9s var(--eo), stroke .35s var(--eo), opacity .35s var(--eo);
  transition-delay:calc(var(--i,0) * 70ms); }

@media (prefers-reduced-motion:reduce){
  .js .deal > *, .js .in .deal > *, .js .deal.in > * {
    opacity:1; transform:none; transition:none; }
  .fx.boot .fx-wires path, .fx.booted .fx-wires path {
    stroke-dashoffset:0; transition:none; }
}

/* ---------- buttons ---------- */
.go {
  display:inline-flex; align-items:center; gap:11px; cursor:pointer;
  padding:16px 30px; border-radius:100px; text-decoration:none;
  font-weight:900; font-size:clamp(14px,1.2vw,16px); letter-spacing:.01em;
  color:var(--amber-ink); background:var(--amber); border:1px solid transparent;
  /* a crisp seated shadow, NOT a coloured halo — the neon dark-mode
     glow is the single most recognisable AI-UI tell. */
  box-shadow:0 1px 0 rgba(255,255,255,.38) inset, 0 6px 18px -6px rgba(0,0,0,.7);
  transition:transform .3s var(--eo), box-shadow .3s var(--eo), background .3s var(--eo);
}
.go:hover { background:#FF7040; transform:translateY(-2px);
  box-shadow:0 1px 0 rgba(255,255,255,.5) inset, 0 12px 26px -8px rgba(0,0,0,.75); }
.go:active { transform:translateY(0) scale(.98); }
.go svg { flex:none; }
.ghost {
  display:inline-flex; align-items:center; gap:9px; cursor:pointer;
  padding:15px 26px; border-radius:100px; text-decoration:none;
  font-weight:700; font-size:clamp(13.5px,1.15vw,15.5px); color:var(--ink);
  border:1px solid var(--hair-2); background:rgba(255,255,255,.02);
  transition:transform .3s var(--eo), background .3s var(--eo), border-color .3s var(--eo);
}
.ghost:hover { background:rgba(255,255,255,.06); border-color:rgba(255,255,255,.32); transform:translateY(-2px); }
.ghost:active { transform:scale(.98); }
.btns { display:flex; gap:14px; flex-wrap:wrap; align-items:center; margin-top:clamp(30px,4.5vh,48px); }

/* ---------- hero ---------- */
#hero { padding-top:20vh; }
.badge { display:inline-flex; align-self:flex-start; align-items:center; gap:10px;
  padding:9px 18px 9px 14px; border-radius:100px; margin-bottom:clamp(20px,3vh,32px);
  font-size:clamp(11.5px,1vw,13.5px); font-weight:900; letter-spacing:.02em; color:#bfe8cf;
  background:rgba(255,90,31,.09); border:1px solid rgba(255,90,31,.3); }
.badge .dot { flex:none; width:7px; height:7px; border-radius:100px; background:var(--amber);
  animation:pulse 2.4s ease-in-out infinite; }
.hero-sub { margin-top:clamp(26px,4vh,44px); }
.cue { position:absolute; bottom:4.5vh; left:clamp(20px,7vw,88px);
       display:flex; align-items:center; gap:11px; font-size:11px;
       color:var(--faint); letter-spacing:.16em; font-weight:500; }
.cue i { display:block; width:1px; height:40px; background:var(--hair); position:relative; overflow:hidden; }
.cue i::after { content:""; position:absolute; inset:-40% 0 auto 0; height:40%;
  background:var(--amber); animation:cue 2.4s var(--eo) infinite; }
@keyframes cue { to { top:132%; } }

@keyframes mar { to { transform:translate3d(-50%,0,0); } }

/* ---------- ruled rows ---------- */
.rows { border-top:1px solid var(--hair); margin-top:clamp(34px,5vh,56px); max-width:900px; }
.row { display:grid; grid-template-columns:minmax(9em,15em) 1fr; gap:clamp(14px,3.4vw,52px);
  padding:clamp(15px,2.2vh,24px) 0; border-bottom:1px solid var(--hair); align-items:start; }
.row dt { font-weight:900; font-size:clamp(18px,1.85vw,25px); letter-spacing:-.02em;
  color:var(--amber); line-height:1.45; }
/* the emphasised lead line above each body paragraph. `b` not `span`:
   a span selector here would also catch the injected phrase units. */
.row dd b { display:block; margin-bottom:7px; color:var(--ink); font-weight:900;
  font-size:clamp(14.5px,1.4vw,18px); letter-spacing:-.01em; line-height:1.65; }
.row dd { font-size:clamp(14px,1.25vw,16.5px); color:var(--sub); line-height:1.95; text-wrap:pretty; }
.row .fig { font-size:clamp(17px,1.7vw,23px); color:var(--amber); font-weight:900; letter-spacing:-.02em; }

/* ---------- timeline ---------- */

/* ---------- device (the one place glass is the point) ---------- */
.stage { display:grid; grid-template-columns:auto minmax(300px,1fr);
  gap:clamp(36px,6vw,92px); align-items:center; }
.float { animation:float 9s ease-in-out infinite alternate; }
@keyframes float { from{transform:translate3d(0,-7px,0)} to{transform:translate3d(0,9px,0)} }
.iphone {
  width:min(328px,80vw); aspect-ratio:390/844; border-radius:44px; position:relative;
  background:linear-gradient(155deg,#4a4e56,#191a1e 26%,#0e0f12 72%,#2b2e34);
  padding:4px;
  /* the jade below the device reads as screen-spill onto the surface,
     not as a halo — it stays under the object, never around it. */
  box-shadow:0 50px 100px -20px rgba(0,0,0,.8), 0 0 0 1px rgba(255,255,255,.07),
             0 34px 60px -34px rgba(255,90,31,.28);
}
.iphone .screen { position:absolute; inset:4px; border-radius:40px; background:#000;
  overflow:hidden; border:6px solid #000; }
.iphone .glare { position:absolute; inset:4px; border-radius:40px; z-index:9; pointer-events:none;
  background:linear-gradient(118deg, rgba(255,255,255,.10) 0%, transparent 26%,
             transparent 72%, rgba(255,255,255,.045) 100%); }
.iphone .island { position:absolute; top:14px; left:50%; transform:translateX(-50%);
  width:100px; height:29px; border-radius:100px; background:#000; z-index:5; }
.iphone .island::after { content:""; position:absolute; right:11px; top:9px; width:11px; height:11px;
  border-radius:100px; background:radial-gradient(circle at 34% 34%, #1e2a36, #000 66%); }
/* THE DEVICE VIEWPORT — the real dashboard demo, running inside the phone.
   Replaces a hand-drawn fake dashboard: the thing being sold is now the thing being shown.

   How it fits: the app is laid out at a true 390px phone width and the whole layer is
   scaled down to whatever the mock screen actually measures (--dvk, set in app.js from
   the rendered width, so it survives the 80vw clamp and any resize). Height is derived
   the other way — calc(100%/k) — so nothing is ever letterboxed, the demo just gets a
   viewport a few pixels taller or shorter than a real handset. Scaling the status bar
   INSIDE that layer is deliberate: a status bar at page scale sitting over an app at
   79% reads instantly as two pictures glued together. */
.dv { position:absolute; inset:0; overflow:hidden; background:#000; }
.dv-scale { position:absolute; top:0; left:0; width:var(--dvbase,100%);
  height:calc(100% / var(--dvk,1));
  transform-origin:0 0; transform:scale(var(--dvk,1)); }
.dv-frame { position:absolute; inset:46px 0 0; width:100%; border:0; display:block;
  background:#000; }
img.dv-frame { height:auto; min-height:calc(100% - 46px); object-fit:cover;
  object-position:top center; }
.dv-live { height:calc(100% - 46px); opacity:0; transition:opacity .24s ease; }

/* State is a class on .dvw, never the `hidden` attribute: every element here declares its
   own `display`, and a class selector outranks the UA's `[hidden]{display:none}` — so
   `el.hidden = true` silently does nothing and you get the poster, the pill AND the live
   app stacked on top of each other. The same trap cost Round 11 a permanently visible
   chart tooltip.
   Two states, not one: `is-live` fires on the tap so the pill leaves immediately, and
   `is-ready` waits for the iframe's load event so the poster is only pulled once there is
   something behind it. Otherwise the phone flashes black for the length of a 3MB boot. */
.dvw:not(.is-live) .dv-off { display:none; }
.dvw.is-live .dv-go { display:none; }
.dvw.is-ready .dv-poster { display:none; }
.dvw.is-ready .dv-live { opacity:1; }

/* The invitation. Dark pill rather than an amber one because it has to hold on a white
   world and a near-black one from the same rule, and it sits over a scrim so it never
   depends on what the poster happens to be showing underneath. */
.dv-go { position:absolute; left:50%; bottom:18px; transform:translateX(-50%);
  display:inline-flex; align-items:center; gap:9px; min-height:44px; padding:11px 20px;
  border-radius:100px; border:1px solid rgba(255,90,31,.55); background:rgba(7,8,11,.86);
  -webkit-backdrop-filter:blur(9px); backdrop-filter:blur(9px);
  color:var(--ink); font-family:var(--goth); font-weight:700; font-size:12.5px;
  letter-spacing:.02em; white-space:nowrap; cursor:pointer; z-index:8;
  box-shadow:0 10px 30px -12px rgba(0,0,0,.9); }
.dv-go i { width:9px; height:9px; border-radius:100px; background:var(--amber); flex:none;
  box-shadow:0 0 0 0 rgba(255,90,31,.55); }
.dv-go:hover { border-color:var(--amber); }
.dv-go:focus-visible { outline:2px solid var(--amber); outline-offset:3px; }
/* one slow ring, and only while it is still asking — 2.6s is far below the frequency
   at which motion becomes noise, and it stops the moment the demo is live */
@media (prefers-reduced-motion:no-preference) {
  .dv-go i { animation:dvping 2.6s cubic-bezier(.22,.61,.36,1) infinite; }
}
@keyframes dvping {
  0%   { box-shadow:0 0 0 0 rgba(255,90,31,.5); }
  70%  { box-shadow:0 0 0 11px rgba(255,90,31,0); }
  100% { box-shadow:0 0 0 0 rgba(255,90,31,0); }
}
/* Closing sits in the switcher row, not on the glass. Inside the bezel a floating ✕ lands
   on the demo's own header and reads as one of ITS controls — the one impression this
   section cannot afford to give. It is also the escape hatch on a phone, where a live
   full-width iframe would otherwise eat every vertical drag. */
.dv-off { color:var(--faint); border-style:dashed; }
.dv-off span[aria-hidden] { font-size:11px; }

/* The column centres its contents with margins, NOT with `align-items:center`. That made
   `.float` a shrink-to-fit flex item taking its width from `.iphone` — at which point every
   percentage and every `auto` inside it resolves against a parent that is itself waiting on
   the child. Chrome and WebKit are both free to break that tie, and they broke it
   differently: upright here, sideways on Guto's phone, and 8×17px once the width was stated
   as a percentage. Nothing in this column is shrink-to-fit any more. */
.dvw { display:block; }
.iphone { margin-inline:auto; }

/* A live app must not bob under the finger. */
.dvw.is-live .float { animation:none; }
.dvw.is-live .glare { opacity:.5; }

/* the trade switcher — each chip carries a swatch of that world's actual ground and accent,
   so the row previews the range before anything is clicked */
.wsw { display:flex; flex-wrap:wrap; gap:8px; justify-content:center;
  margin-top:clamp(18px,2.6vh,26px); }
.ws { display:inline-flex; align-items:center; gap:9px; min-height:44px; padding:10px 16px;
  border-radius:100px; border:1px solid var(--hair); background:rgba(255,255,255,.03);
  color:var(--sub); font-family:var(--goth); font-weight:700; font-size:13px;
  cursor:pointer; transition:color .2s var(--eo), border-color .2s var(--eo),
    background-color .2s var(--eo); }
.ws .sw { width:15px; height:15px; border-radius:5px; flex:none;
  background:var(--sw-bg); border:1.5px solid var(--sw-ac); }
.ws:hover { color:var(--ink); border-color:rgba(255,255,255,.22); }
.ws[aria-pressed="true"] { color:var(--ink); border-color:var(--amber);
  background:rgba(255,90,31,.1); }
.ws:focus-visible { outline:2px solid var(--amber); outline-offset:3px; }
.wsn { margin:14px auto 0; max-width:34em; text-align:center; color:var(--faint);
  font-size:12.5px; line-height:1.85; }
.bar { position:absolute; top:15px; inset-inline:0; padding:0 25px; display:flex;
  justify-content:space-between; font-size:13px; font-weight:700; z-index:6; }
.bar .sig { display:flex; gap:5px; align-items:center; }
.bar .bars i { display:inline-block; width:2.6px; background:#fff; border-radius:1px; margin-right:1px; }
.batt { width:22px; height:11px; border:1px solid rgba(255,255,255,.5); border-radius:3px; position:relative; }
.batt::before { content:""; position:absolute; inset:1.5px; right:5.5px; background:#fff; border-radius:1px; }
.batt::after { content:""; position:absolute; right:-3.4px; top:3px; width:2px; height:4.4px;
  background:rgba(255,255,255,.5); border-radius:0 1px 1px 0; }

/* each item in its own quiet panel — a wall of ticked lines is hard to
   read; a bounded block per idea is not */
/* :not(.u) is load-bearing — a bare `span` selector here outranks
   `.u{display:inline-block}` and would turn every phrase unit into a
   block, stacking the text one word per line. */

/* ---------- the diagram ----------
   A real drawn schematic: icon nodes, curved wires with arrowheads,
   particles running the wires, and stages that draw themselves in as the
   section scrolls. SVG carries the graphics; the stage captions are HTML
   chips positioned over it by percentage, so they keep proper Japanese
   typography and swap language with everything else. */
.dia { position:relative; margin:clamp(26px,4vh,44px) auto 0; max-width:560px; }
.dia svg { display:block; width:100%; height:auto; overflow:visible; }

/* wires */
.wire-p { fill:none; stroke:var(--hair-2); stroke-width:1.6; stroke-linecap:round; }
.js .wire-p { stroke-dasharray:var(--len); stroke-dashoffset:var(--len); }
.js .on .wire-p { stroke-dashoffset:0; transition:stroke-dashoffset 1.1s var(--eo); }
.on .wire-p { stroke:rgba(255,90,31,.55); }
/* the loop keeps its dash pattern, so it fades in rather than drawing —
   a dashoffset tween on a 5/7 dash just shuffles the dashes */
.wire-p.loop { stroke-dasharray:5 7 !important; stroke-dashoffset:0 !important;
  stroke:rgba(255,90,31,.3); stroke-width:1.4; }
.js .wire-p.loop { opacity:0; }
.js .on .wire-p.loop { opacity:1; transition:opacity .9s var(--eo) .35s; }

/* nodes */
.nd { transform-box:fill-box; transform-origin:center; }
.js .nd { opacity:0; transform:scale(.72); }
.js .on .nd { opacity:1; transform:none;
  transition:opacity .55s var(--eo), transform .75s var(--eo); }
.nd .box { fill:rgba(255,255,255,.045); stroke:var(--hair-2); stroke-width:1.4; }
.on .nd .box { fill:rgba(255,90,31,.09); stroke:rgba(255,90,31,.55); }
.nd .ico { fill:none; stroke:var(--sub); stroke-width:1.9;
  stroke-linecap:round; stroke-linejoin:round; }
.on .nd .ico { stroke:var(--amber); }
.nd .box, .nd .ico { transition:fill .6s var(--eo), stroke .6s var(--eo); }
/* the label lands after its node — text follows the picture */
.lbl { fill:var(--sub); font-family:var(--goth); font-weight:700; font-size:13px;
  text-anchor:middle; }
.js .lbl { opacity:0; transform:translateY(6px); transform-box:fill-box; }
.js .on .lbl { opacity:1; transform:none;
  transition:opacity .5s var(--eo) .3s, transform .5s var(--eo) .3s; }

/* the auto-process core */
.core .disc { fill:#08120e; stroke:var(--amber); stroke-width:2; }
.core .ring { fill:none; stroke:rgba(255,90,31,.4); stroke-width:1.2;
  transform-box:fill-box; transform-origin:center; animation:spin 16s linear infinite; }
.core .ring.r2 { stroke:rgba(255,90,31,.22); stroke-dasharray:2 8;
  animation-duration:26s; animation-direction:reverse; }
.core .ring.r1 { stroke-dasharray:9 11; }
.core .glyph { fill:var(--amber); }
/* 19px suited the old two-character label; the Japanese one is four
   characters and rendered 81px wide inside a 96px disc, leaving ~2px of
   clearance at the text's baseline. Sized to sit comfortably instead. */
.core .cap { fill:var(--amber); font-family:var(--goth); font-weight:900;
  font-size:15px; text-anchor:middle; letter-spacing:.04em; }
html[lang="en"] .core .cap { font-size:18px; letter-spacing:.08em; }
.js .core { opacity:0; transform-box:fill-box; transform-origin:center; transform:scale(.6); }
.js .on .core { opacity:1; transform:none;
  transition:opacity .6s var(--eo), transform .95s var(--eo); }
.on .core .disc { filter:drop-shadow(0 0 16px rgba(255,90,31,.5)); }

/* particles running the wires */
.pk { fill:#dfffee; }
.on .pk { filter:drop-shadow(0 0 5px var(--amber)); }

/* stage captions: compact single-line chips that ride the flow line and
   mask the wire behind them, so they read as labelled junctions */
.cap-chip { position:absolute; left:50%; z-index:2; white-space:nowrap;
  display:flex; align-items:center; gap:8px;
  background:var(--bg); border:1px solid var(--hair-2); border-radius:100px;
  padding:7px 16px 7px 9px;
  font-size:clamp(12.5px,1.2vw,15px); font-weight:900; letter-spacing:-.01em;
  transform:translate(-50%,-50%);
  transition:border-color .6s var(--eo), background .6s var(--eo),
             opacity .55s var(--eo), transform .6s var(--eo); }
.js .cap-chip { opacity:0; transform:translate(-50%,calc(-50% + 12px)); }
.js .cap-chip.lit { opacity:1; transform:translate(-50%,-50%); }
.cap-chip.lit { border-color:rgba(255,90,31,.5); background:#08120e; }
.cap-chip em { font-style:normal; flex:none; display:grid; place-items:center;
  width:22px; height:22px; border-radius:100px; font-size:12px;
  color:var(--amber-ink); background:var(--amber); }

/* ── how-it-works: ownership boundary + pipeline examples ──────────────
   Everything here is hw- prefixed. HANDOVER trap 3: .stage once collided
   with the phone wrapper and silently crushed this infographic. */

/* the boundary that says "all of this is yours" */
.hw-bnd { fill:rgba(255,90,31,.028); stroke:var(--hair-2); stroke-width:1.4;
  stroke-dasharray:3 7;
  transition:stroke .7s var(--eo), fill .7s var(--eo), opacity .8s var(--eo); }
.on .hw-bnd { stroke:rgba(255,90,31,.42); }
.js .hw-bnd { opacity:0; }
.js .on .hw-bnd { opacity:1; }

.hw-own { fill:var(--amber); font-family:var(--goth); font-weight:900;
  font-size:14px; letter-spacing:.02em; }
.js .hw-own { opacity:0; }
.js .on .hw-own { opacity:1; transition:opacity .6s var(--eo) .06s; }

/* CoreBuild, deliberately outside the boundary — pill, not a client node */
.hw-cbo rect { fill:#08120e; stroke:var(--amber); stroke-width:1.6; }
.hw-cbo text { fill:#fff; font-family:var(--goth); font-weight:900;
  font-size:17px; letter-spacing:.06em; }
.hw-cbo .hw-cbn { fill:var(--sub); font-weight:600; font-size:12.5px;
  letter-spacing:0; }
.js .hw-cbo { opacity:0; transform:translateY(-8px); transform-box:fill-box; }
.js .on .hw-cbo { opacity:1; transform:none;
  transition:opacity .6s var(--eo), transform .6s var(--eo); }
.hw-reach { fill:none; stroke:rgba(255,90,31,.5); stroke-width:1.5;
  stroke-dasharray:4 6; stroke-linecap:round; }
.js .hw-reach { opacity:0; }
.js .on .hw-reach { opacity:1; transition:opacity .6s var(--eo) .18s; }

/* shape carries meaning: squares already exist · the one circle transforms ·
   sharp rectangles are records · pills are what you actually look at */
.hw-rec { rx:7; }
.on .nd .hw-use { fill:rgba(255,90,31,.16); }
.hw-glow { opacity:0; transition:opacity 1.1s var(--eo) .2s; }
.on .hw-glow { opacity:1; }
.hw-loop { fill:var(--sub); font-family:var(--goth); font-weight:700;
  font-size:13px; letter-spacing:.02em; opacity:.75; }
.js .hw-loop { opacity:0; }
.js .on .hw-loop { opacity:.75; transition:opacity .7s var(--eo) .45s; }

/* pipeline examples — the shape, then four instances of the shape */
.hw-pipes { margin:clamp(30px,4.6vh,52px) auto 0; max-width:640px; }
.hw-pipes > p { color:var(--sub); font-size:clamp(14px,1.5vw,16.5px);
  font-weight:700; margin-bottom:clamp(14px,2vh,20px); }
.hw-pipe { display:grid; gap:4px 14px; padding:clamp(14px,2.2vh,18px) 0;
  border-top:1px solid var(--hair-2);
  grid-template-columns:auto 1fr; align-items:baseline; }
.hw-pipe:last-child { border-bottom:1px solid var(--hair-2); }
.hw-pipe b { grid-column:1; grid-row:1 / span 2; align-self:center;
  display:grid; place-items:center; width:38px; height:38px; border-radius:11px;
  background:rgba(255,90,31,.1); border:1px solid rgba(255,90,31,.3); }
.hw-pipe b svg { width:19px; height:19px; fill:none; stroke:var(--amber);
  stroke-width:1.9; stroke-linecap:round; stroke-linejoin:round; }
.hw-pipe .hw-in { grid-column:2; font-weight:800; color:var(--ink);
  font-size:clamp(14.5px,1.55vw,17px); letter-spacing:-.01em; }
.hw-pipe .hw-out { grid-column:2; color:var(--sub);
  font-size:clamp(13px,1.35vw,15px); font-weight:600; line-height:1.6; }
.hw-pipe .hw-out i { font-style:normal; color:var(--amber); font-weight:800; }

@media (max-width:520px){
  .lbl { font-size:17px; }
  .cap-chip { padding:6px 13px 6px 7px; }
  .hw-own { font-size:16px; }
  .hw-pipe { gap:3px 12px; }
  .hw-pipe b { width:34px; height:34px; }
}
@media (prefers-reduced-motion:reduce){
  .core .ring { animation:none !important; }
  /* reduced motion removes movement, not the fades that carry meaning */
  .js .hw-cbo { transform:none; }
}

/* ---------- the loop callout + results, under the diagram ---------- */
.back { display:flex; align-items:flex-start; gap:14px; flex-wrap:nowrap;
  margin-top:clamp(24px,3.6vh,38px);
  padding:clamp(16px,2.4vh,22px) clamp(16px,2.2vw,26px);
  border:1px solid rgba(255,90,31,.32); border-radius:18px;
  background:linear-gradient(150deg, rgba(255,90,31,.09), rgba(255,90,31,.02) 60%); }
.back svg { flex:none; margin-top:2px; animation:spin 11s linear infinite; }
.back p { font-size:clamp(13px,1.15vw,15.5px); color:var(--sub); line-height:1.85; }
.back b { color:var(--amber); font-weight:900; }

.gains { display:grid; grid-template-columns:repeat(auto-fit,minmax(190px,1fr));
  gap:clamp(10px,1.6vw,16px); margin-top:clamp(14px,2vh,20px); }
.gains div { background:rgba(255,255,255,.028); border:1px solid var(--hair);
  border-radius:16px; padding:clamp(14px,2vh,18px) clamp(14px,1.8vw,20px);
  transition:background .4s var(--eo), border-color .4s var(--eo); }
.gains div:hover { background:rgba(255,90,31,.05); border-color:rgba(255,90,31,.3); }
.gains p { font-size:clamp(11.5px,1vw,13px); color:var(--faint); font-weight:700;
  letter-spacing:.02em; }
.gains .was { display:inline-block; margin-top:7px; font-size:clamp(12px,1.05vw,13.5px);
  color:var(--faint); text-decoration:line-through;
  text-decoration-color:rgba(255,255,255,.28); }
.gains .now { display:inline-block; margin-left:9px; font-size:clamp(17px,1.7vw,23px);
  font-weight:900; color:var(--amber); letter-spacing:-.02em; }

@media (max-width:640px){
  .back { gap:11px; padding:15px 16px; }
}

/* ---------- pricing (glass, spent deliberately) ---------- */
.panel { margin-top:clamp(30px,4.5vh,50px); border-radius:24px; overflow:hidden;
  background:linear-gradient(168deg, rgba(255,255,255,.062), rgba(255,255,255,.018) 52%);
  -webkit-backdrop-filter:blur(20px) saturate(1.4); backdrop-filter:blur(20px) saturate(1.4);
  border:1px solid var(--hair-2);
  box-shadow:0 30px 70px -30px rgba(0,0,0,.8), inset 0 1px 0 rgba(255,255,255,.14); }
.pt { width:100%; border-collapse:collapse; }
.pt th { text-align:left; font-size:clamp(11px,.95vw,13px); color:var(--faint); font-weight:700;
  padding:22px clamp(14px,2vw,26px) 14px; border-bottom:1px solid var(--hair); }
.pt td { padding:clamp(15px,2.1vh,22px) clamp(14px,2vw,26px); border-bottom:1px solid var(--hair);
  vertical-align:baseline; }
.pt tr:last-child td { border-bottom:none; }
.pt tbody tr { transition:background .35s var(--eo); }
.pt tbody tr:hover { background:rgba(255,255,255,.028); }
.pt .plan { font-weight:900; font-size:clamp(15px,1.4vw,19px); white-space:nowrap; letter-spacing:-.01em; }
.pt .n { font-weight:700; white-space:nowrap; font-size:clamp(13.5px,1.35vw,17px); }
.pt .what { color:var(--sub); font-size:clamp(12.5px,1.1vw,14.5px); line-height:1.8; }
.pt tr.pick { background:rgba(255,90,31,.05); }
.pt tr.pick:hover { background:rgba(255,90,31,.075); }
.pt tr.pick .plan, .pt tr.pick .n { color:var(--amber); }
.tag { display:inline-block; font-size:10px; font-weight:900; letter-spacing:.06em;
  color:var(--amber-ink); background:var(--amber); border-radius:100px;
  padding:3px 10px; margin-left:10px; vertical-align:2px; }
.note { margin-top:clamp(20px,3vh,30px); font-size:clamp(12.5px,1.05vw,14px);
  color:var(--sub); line-height:1.95; max-width:62em;
  background:linear-gradient(168deg, rgba(255,255,255,.05), rgba(255,255,255,.016) 60%);
  border:1px solid var(--hair);
  border-radius:16px; padding:clamp(16px,2.2vh,22px) clamp(16px,2vw,24px); }
.note p + p { margin-top:clamp(13px,1.9vh,19px); padding-top:clamp(13px,1.9vh,19px);
  border-top:1px solid var(--hair); }
.note b { display:block; margin-bottom:6px; color:var(--amber); font-weight:900; }

/* ---------- build tiers (cumulative) ----------
   Colour carries the ladder here: teal → jade → spring is depth, not
   decoration, and the same three read again as the column heads of the
   comparison table so the two blocks are obviously one idea. */
.bt { margin-top:clamp(24px,3.4vh,38px); display:grid; align-items:stretch;
  gap:clamp(12px,1.6vw,18px); grid-template-columns:repeat(4,1fr); }
.bt--two { grid-template-columns:repeat(2,1fr); max-width:880px; }
/* Enterprise withdrawn 2026-09-07 (Guto) — the build section is one card now.
   The [data-t="ent"] / [data-ent] rules below are kept, inert, so the tier can
   be reinstated without rebuilding the styling. */
.bt--one { grid-template-columns:1fr; }
.bt-c { position:relative; overflow:hidden; border-radius:18px;
  border:1px solid var(--hair); padding:clamp(19px,2.7vh,26px) clamp(15px,1.7vw,21px);
  background:linear-gradient(168deg, rgba(255,255,255,.05), rgba(255,255,255,.015) 60%);
  transition:border-color .4s var(--eo), background .4s var(--eo), transform .3s var(--eo); }
.bt-c::before { content:""; position:absolute; inset:0 0 auto 0; height:3px;
  background:var(--tone); opacity:.9; }
.bt-c[data-t="base"]  { --tone:var(--amber); }  /* the primary offer leads in brand */
.bt-c[data-t="mid"]   { --tone:var(--amber); }
.bt-c[data-t="full"]  { --tone:var(--amber-dim); }
.bt-c[data-t="ent"]   { --tone:var(--brass); }
@media (hover:hover) and (pointer:fine){
  .bt-c:hover { transform:translateY(-2px);
    border-color:color-mix(in srgb, var(--tone) 42%, transparent);
    background:linear-gradient(168deg,
      color-mix(in srgb, var(--tone) 9%, rgba(255,255,255,.05)), rgba(255,255,255,.015) 60%); }
}
.bt-n { font-size:clamp(14px,1.35vw,17px); font-weight:900; color:var(--tone);
  letter-spacing:.01em; }
.bt-p { margin-top:9px; font-size:clamp(19px,1.95vw,26px); font-weight:900;
  color:var(--ink); letter-spacing:-.025em; }
.bt-p > span:not(.u) { font-size:.5em; font-weight:700; color:var(--faint);
  letter-spacing:0; margin-left:.4em; }
/* provisional marker — these numbers are NOT decided, and the page must not
   let anyone mistake them for a quote */
.prov { display:inline-block; margin-left:7px; padding:2.5px 8px; border-radius:100px;
  font-size:10px; font-weight:900; letter-spacing:.08em; vertical-align:3px;
  color:var(--brass); background:rgba(216,169,75,.12);
  border:1px solid rgba(216,169,75,.4); }
.bt-inc { margin-top:13px; padding:8px 11px; border-radius:10px; font-size:clamp(11.5px,1vw,12.5px);
  font-weight:700; color:var(--sub); line-height:1.7;
  background:color-mix(in srgb, var(--tone) 8%, transparent);
  border:1px solid color-mix(in srgb, var(--tone) 26%, transparent); }
.bt-d { margin-top:13px; font-size:clamp(12px,1.08vw,13.5px); color:var(--sub); line-height:1.85; }
.bt-l { list-style:none; margin-top:13px; display:grid; gap:7px; }
.bt-l li { position:relative; padding-left:17px; font-size:clamp(12px,1.08vw,13.5px);
  color:var(--ink); font-weight:600; line-height:1.7; }
.bt-l li::before { content:""; position:absolute; left:0; top:.62em; width:7px; height:7px;
  border-radius:2px; background:var(--tone); opacity:.85; }

/* ---------- what changes between tiers ---------- */
.cmp-wrap { overflow-x:auto; }
.cmp-hint { display:none; margin-top:9px; font-size:12px; color:var(--faint);
  font-weight:600; letter-spacing:.02em; }
.cmp { width:100%; border-collapse:collapse; }
.cmp th, .cmp td { padding:clamp(11px,1.6vh,16px) clamp(9px,1.2vw,16px);
  border-bottom:1px solid var(--hair); text-align:center;
  font-size:clamp(11.5px,1.02vw,13.5px); font-weight:700; color:var(--ink); }
.cmp th:first-child, .cmp td:first-child { text-align:left; white-space:nowrap;
  color:var(--sub); font-weight:700; }
.cmp thead th { color:var(--faint); font-weight:900; letter-spacing:.05em;
  font-size:clamp(11px,.95vw,12.5px); }
.cmp thead th[data-t="base"] { color:var(--teal); }
.cmp thead th[data-t="mid"]  { color:var(--amber); }
.cmp thead th[data-t="full"] { color:var(--spring); }
.cmp thead th[data-t="ent"]  { color:var(--brass); }
.cmp tbody tr:last-child td { border-bottom:none; }
.cmp tbody tr { transition:background .35s var(--eo); }
.cmp tbody tr:hover { background:rgba(255,255,255,.028); }
.cmp .yes { color:var(--jade); font-weight:900; }
.cmp .dim { color:var(--faint); font-weight:600; }

/* ---------- the paid diagnosis, ahead of every plan ----------
   It is a step, not a tier, so it must not read as a fifth card: full width,
   jade-led, sitting above the ladder (Guto, 2026-08-20). */
.bt-pre { margin-top:clamp(24px,3.4vh,38px); display:grid; gap:clamp(14px,2.4vw,30px);
  grid-template-columns:1fr auto; align-items:center;
  padding:clamp(18px,2.6vh,24px) clamp(18px,2.2vw,28px); border-radius:18px;
  background:linear-gradient(168deg, rgba(255,90,31,.10), rgba(255,90,31,.035) 60%);
  border:1px solid rgba(255,90,31,.34);
  -webkit-backdrop-filter:blur(16px) saturate(1.3); backdrop-filter:blur(16px) saturate(1.3); }
.bt-pre-n { font-size:clamp(14px,1.4vw,17px); font-weight:900; color:var(--amber);
  letter-spacing:.01em; }
.bt-pre-d { margin-top:8px; font-size:clamp(12.5px,1.12vw,14px); color:var(--sub);
  line-height:1.85; max-width:64ch; }
.bt-pre-p { font-size:clamp(20px,2vw,27px); font-weight:900; color:var(--ink);
  letter-spacing:-.025em; white-space:nowrap; }
.bt-pre-p > span:not(.u) { font-size:.48em; font-weight:700; color:var(--faint);
  letter-spacing:0; margin-left:.4em; }
/* the monthly Enterprise level is quoted, not listed — brass marks it as the
   custom one, matching its build-tier card */
.tiers > div[data-ent] { border-color:rgba(216,169,75,.34); }
.tiers > div[data-ent] .t { color:var(--brass); }
.tiers > div[data-ent] .p { font-size:clamp(17px,1.7vw,22px); }
@media (max-width:620px){
  .bt-pre { grid-template-columns:1fr; gap:12px;
    -webkit-backdrop-filter:none; backdrop-filter:none;
    background:linear-gradient(168deg, rgba(255,90,31,.13), #0c0f14 62%); }
}


/* how much of a folder actually stops being manual. The page used to claim
   "the green ones are automated", which was simply false — 01_経理 is brass
   and every row in it is automated (Guto, 2026-08-20). Colour encodes the
   KIND of work; this badge encodes the automation, per folder. */
.fx-auto { font-size:9.5px; font-weight:900; letter-spacing:.04em;
  color:var(--jade); background:rgba(15,203,136,.11);
  border:1px solid rgba(15,203,136,.3); border-radius:100px; padding:2px 8px;
  white-space:nowrap; }
/* a folder nobody automates is not a failure — it is the deliberate case */
.fx-auto[data-hand] { color:var(--sub); background:rgba(255,255,255,.05);
  border-color:var(--hair-2); }

/* the colour key. Three tones have been on this page since it was built and
   nothing ever said what they meant. */
.fx-legend { margin-top:clamp(12px,1.8vh,18px); }
.fx-legend .lg-fold { width:22px; height:auto; flex:none; }
.fx-legend .sv-lg[data-tone="money"] { color:var(--brass); }
.fx-legend .sv-lg[data-tone="ops"]   { color:var(--jade); }
.fx-legend .sv-lg[data-tone="ref"]   { color:var(--teal); }
.fx-legend .lg-fold path { fill:currentColor; }

/* ---------- glass panels ----------------------------------------------
   Every surface that holds information gets the same material: the sky
   blurs behind it instead of reading through it. The comparison table was
   the reference (Guto, 2026-08-20 — "the animation goes behind the panel").
   PERF: dropped to an opaque fill under 620px, per the banner rule at the
   top of this file — a dozen live backdrop-filters is where phone GPUs
   give up, and the sky is already faded to .10–.24 there anyway. */
.bt-c, .tiers > div, .note, .sv-a, .hw-card, .hw-col, .pr-nd, .fx-f {
  -webkit-backdrop-filter:blur(16px) saturate(1.3);
  backdrop-filter:blur(16px) saturate(1.3);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.08),
             0 18px 44px -26px rgba(0,0,0,.72); }
@media (max-width:620px){
  .bt-c, .tiers > div, .note, .sv-a, .hw-card, .hw-col, .pr-nd, .fx-f {
    -webkit-backdrop-filter:none; backdrop-filter:none;
    background:linear-gradient(168deg, #12161c, #0c0f14 62%); }
}

/* ---------- monthly tiers ---------- */
.tiers-h { margin-top:clamp(34px,5vh,54px); font-size:clamp(19px,2vw,27px); font-weight:900;
  letter-spacing:-.015em; color:var(--amber); }
.tiers { display:grid; grid-template-columns:repeat(auto-fit,minmax(215px,1fr));
  gap:clamp(11px,1.6vw,16px); margin-top:clamp(18px,2.6vh,26px); }
.tiers > div { border-radius:18px; padding:clamp(18px,2.6vh,24px) clamp(16px,2vw,22px);
  background:linear-gradient(168deg, rgba(255,255,255,.055), rgba(255,255,255,.018) 60%);
  border:1px solid var(--hair);
  transition:background .4s var(--eo), border-color .4s var(--eo); }
.tiers > div:hover { background:rgba(255,90,31,.05); border-color:rgba(255,90,31,.3); }
.tiers .t { font-size:clamp(12px,1.05vw,13.5px); font-weight:900; letter-spacing:.06em;
  color:var(--amber); }
.tiers .p { margin-top:8px; font-size:clamp(21px,2.1vw,28px); font-weight:900;
  letter-spacing:-.025em; color:var(--ink); }
/* > span:not(.u) — the Japanese line-breaker injects .u spans as direct
   children, so a bare `.tiers .p span` shrinks the price itself to 10.5px
   grey. Only the real suffix element may take this. */
.tiers .p > span:not(.u) { font-size:.5em; font-weight:700; color:var(--faint);
  letter-spacing:0; margin-left:.4em; }
.tiers .d { margin-top:10px; font-size:clamp(12.5px,1.1vw,14px); color:var(--sub); line-height:1.8; }

.tiers-note { margin-top:clamp(12px,1.8vh,16px); font-size:clamp(11.5px,1vw,13px);
  color:var(--faint); line-height:1.8; }
/* the "works without an AI account" caveat, under the AI row.
   A tinted block, not a side stripe. */
.opt { display:block; margin-top:11px; padding:10px 13px; border-radius:11px;
  font-style:normal; background:rgba(255,90,31,.06);
  border:1px solid rgba(255,90,31,.22); color:var(--sub);
  font-size:.92em; line-height:1.8; }

/* ---------- closing checklist ---------- */
/* `i`, not `span`, for the parenthetical: a span selector here would also
   catch the units the Japanese line-breaker injects. */
.checks { list-style:none; margin-top:clamp(24px,3.4vh,34px); display:grid;
  gap:clamp(9px,1.3vh,13px); max-width:36em; }
.checks li { position:relative; padding-left:31px; color:var(--ink);
  font-size:clamp(13.5px,1.25vw,16.5px); font-weight:700; line-height:1.75; }
.checks li::before { content:""; position:absolute; left:4px; top:.62em;
  width:11px; height:6.5px; border-left:2px solid var(--jade);
  border-bottom:2px solid var(--jade); transform:rotate(-45deg); }
.checks i { font-style:normal; font-weight:400; color:var(--sub); }
.ask { margin-top:clamp(24px,3.6vh,36px); font-family:var(--mincho); font-weight:600;
  font-size:clamp(17px,1.9vw,26px); line-height:1.75; letter-spacing:-.01em;
  text-wrap:balance; }

/* ---------- contact ---------- */
.contact { margin-top:clamp(30px,4.5vh,48px); display:flex; flex-wrap:wrap; gap:12px 40px;
  padding-top:clamp(24px,3.4vh,34px); border-top:1px solid rgba(255,90,31,.24); }
.contact div { font-size:14px; }
.contact dt { font-size:11px; font-weight:900; letter-spacing:.1em; color:var(--amber); margin-bottom:5px; }
.contact dd { font-weight:700; font-size:clamp(15px,1.4vw,18px); }

/* the footer signature: the wordmark itself, not the site's serif set in caps.
   Only the entity name is live text — the image must survive setLang()'s
   innerHTML swap, so data-en sits on the inner span, never on the <p>. */
.fbrand { display:inline-flex; align-items:center; gap:9px; }
.fbrand .fwm { height:15px; width:auto; opacity:.92; }
.fbrand .fsep { color:rgba(255,255,255,.22); }

footer { padding:clamp(30px,5vh,52px) clamp(20px,7vw,88px); border-top:1px solid var(--hair);
  display:flex; flex-wrap:wrap; gap:14px 30px; justify-content:space-between; align-items:center;
  font-size:12.5px; color:var(--faint); position:relative; z-index:var(--z-content);
  background:var(--bg); }

/* ---------- responsive ---------- */
@media (max-width:900px) {
  .stage { grid-template-columns:1fr; justify-items:center; gap:clamp(34px,6vh,54px); }

}
@media (max-width:640px) {
  section { padding:13vh clamp(20px,7vw,88px); }
  section.short { padding:0; }
  /* the objects are fixed-size, so on a 375px screen they read as
     foreground clutter rather than distant atmosphere — shrink and
     fade them until they sit behind the copy again. Scale the child
     svg, not .obj: the bob keyframes own .obj's transform. */
  #sky .obj svg { transform:scale(.62); }
  .far { opacity:.10; } .mid { opacity:.17; } .near { opacity:.24; }
  .row { grid-template-columns:1fr; gap:8px; }
  .btns { flex-direction:column; align-items:stretch; }
  .go, .ghost { justify-content:center; }
  /* build tiers stack; the comparison keeps its columns and scrolls inside
     its own box — stacking a 5-column matrix destroys the comparison it
     exists to make */
  .bt { grid-template-columns:1fr; }
  /* .panel.cmp-wrap, not .cmp-wrap: the element carries BOTH classes, and
     the .panel mobile rule below sets overflow:visible. Equal specificity
     meant .panel won on source order, so the table was clipped by the
     html,body overflow-x:clip and could not be reached at all — the whole
     comparison was unreadable on a phone (Guto, on device, 2026-08-20). */
  .panel.cmp-wrap { overflow-x:auto; -webkit-overflow-scrolling:touch;
    border:1px solid var(--hair-2); border-radius:16px;
    background:linear-gradient(168deg, #12161c, #0c0f14 62%); }
  .cmp { min-width:560px; }
  /* nothing on screen says a table can be dragged, so say it */
  .cmp-hint { display:block; }
  .cmp th:first-child, .cmp td:first-child { position:sticky; left:0;
    background:#0a0c10; }
  /* pricing table → stacked records */
  .panel { background:none; border:none; box-shadow:none; backdrop-filter:none;
    -webkit-backdrop-filter:none; border-radius:0; overflow:visible; }
  .pt, .pt tbody, .pt tr, .pt td { display:block; }
  .pt thead { display:none; }
  .pt tr { border-radius:18px; padding:20px 22px; margin-bottom:14px;
    background:linear-gradient(168deg, rgba(255,255,255,.06), rgba(255,255,255,.02));
    border:1px solid var(--hair-2); }
  .pt td { border:none; padding:4px 0; }
  .pt td.n::before { content:attr(data-l) "　"; color:var(--faint); font-weight:700; font-size:12px; }
  html[data-lang="en"] .pt td.n::before { content:attr(data-dl) "  "; }
  /* comparison → stacked records */
            }

@media (max-width:700px) {
  /* THE PHONE KEEPS ITS FRAME ON MOBILE, AT REAL PROPORTIONS (Guto, 2026-09-01, in two
     passes: the frame back first, then "it looks like a very short phone — make it smaller
     but make the height make sense").

     HEIGHT is the definite dimension and the width follows from the 390:844 aspect. Doing it
     the other way round — a full-width frame clamped by max-height — keeps the width and
     squashes the shape, which is what produced the short phone. A narrower device is the
     trade he chose, and it costs some scale: the app is laid out at 320 (its tested floor)
     and mapped onto whatever screen that leaves. */
  /* WIDTH-DRIVEN, NEVER HEIGHT-DRIVEN. This was `height:…; width:auto` with the ratio left
     to fill in the width, and it rendered as a SIDEWAYS phone on Guto's device (2026-09-01)
     while Chrome drew it upright. The construct is circular: `.float` is a flex item under
     `align-items:center`, so it is shrink-to-fit and takes its width from `.iphone` — whose
     `width:auto` is meanwhile being resolved against `.float`. Engines are free to break that
     tie differently, and Blink and WebKit do.
     One definite dimension removes the circularity: the width is stated outright and the
     ratio derives the height, exactly as on desktop. The `vh` line is a fallback for engines
     without `svh` — without it an unknown unit invalidates the declaration and the phone
     collapses to nothing. 296px is 640 × 390/844, i.e. the same cap expressed as a width. */
  /* Every term is a viewport unit or an absolute length, so the width is definite no matter
     what the parent is doing, and the ratio derives the height from it. The first term is the
     column width restated from the viewport — `section` padding is clamp(20px,7vw,88px) a
     side. The `vh` line is the fallback for engines without `svh`: an unknown unit
     invalidates the whole declaration, and a phone with no width is a phone you cannot see. */
  .dvw .iphone { width:min(calc(100vw - 2 * clamp(20px, 7vw, 88px)), calc(76vh * 390 / 844), 296px); height:auto; }
  .dvw .iphone { width:min(calc(100vw - 2 * clamp(20px, 7vw, 88px)), calc(76svh * 390 / 844), 296px); }
  .dvw .float { animation:none; }
  .wsw { gap:6px; }
  .ws { padding:10px 12px; font-size:12px; gap:7px; }
  .ws .sw { width:13px; height:13px; border-radius:4px; }
}

@media (prefers-reduced-motion:reduce) {
  html { scroll-behavior:auto; }
  .blob,.bob,.bob2,.bob3,.bob4,.bob5,.bob6,.cue i::after,.float,
  .live i,section.drench::after,.rail span,.spark { animation:none !important; }
  .js .rv,.js .rv-l,.js .rv-s { transform:none; }
  .js .in .rv,.js .in .rv-l,.js .in .rv-s { transition:opacity .3s ease; }
  .js .mask > span { transform:none; opacity:0; }
  .js .in .mask > span { opacity:1; transition:opacity .35s ease; }
  .js .cline { stroke-dashoffset:0; }
  .js .wk i { transform:none; }
}

/* ── site navigation ──────────────────────────────────────────────────────
   Added 2026-08-12 when the single page became a multi-page site. .nav,
   .burger and .drawer were all confirmed unused before naming (HANDOVER
   trap 3: a class-name collision once silently crushed the infographic). */

.nav { display:flex; align-items:center; gap:clamp(16px,2.4vw,34px); margin-right:auto;
  margin-left:clamp(20px,3.4vw,52px); }
.nav a { color:var(--sub); font-size:15px; font-weight:700; letter-spacing:.02em;
  text-decoration:none; position:relative; padding:6px 0;
  transition:color .35s var(--eo); }
.nav a::after { content:""; position:absolute; left:0; right:0; bottom:0; height:1.5px;
  background:var(--amber); transform:scaleX(0); transform-origin:0 50%;
  transition:transform .32s var(--eo); }
@media (hover:hover) and (pointer:fine){
  .nav a:hover { color:var(--ink); }
  .nav a:hover::after { transform:scaleX(1); }
}
/* the page you are on: stated, not merely hinted */
.nav a[aria-current="page"] { color:var(--ink); }
.nav a[aria-current="page"]::after { transform:scaleX(1); }

.burger { display:none; flex-direction:column; justify-content:center; gap:6px;
  width:44px; height:44px; padding:0 11px; background:none; border:0; cursor:pointer; }
.burger i { display:block; height:1.8px; background:var(--ink); border-radius:2px;
  transition:transform .34s var(--eo), opacity .24s var(--eo); }
.burger[aria-expanded="true"] i:first-child { transform:translateY(3.9px) rotate(45deg); }
.burger[aria-expanded="true"] i:last-child  { transform:translateY(-3.9px) rotate(-45deg); }

.drawer { position:fixed; inset:var(--hd-h,68px) 0 auto 0; z-index:calc(var(--z-header) - 1);
  display:none; flex-direction:column; padding:14px clamp(20px,7vw,88px) 26px;
  background:rgba(7,8,11,.97); border-bottom:1px solid var(--hair-2);
  backdrop-filter:blur(14px); }
.drawer[hidden] { display:none; }
.drawer.open { display:flex; }
.drawer a { color:var(--ink); text-decoration:none; font-size:19px; font-weight:700;
  padding:15px 0; border-bottom:1px solid rgba(255,255,255,.07); letter-spacing:.02em; }
.drawer a:last-child { border-bottom:0; color:var(--amber); }

@media (max-width:900px){
  .nav { display:none; }
  .burger { display:flex; }
  .hd .right .go { display:none; }
}

/* ── how.html — the explainer page ────────────────────────────────────────
   Added 2026-08-12. All hw- prefixed and checked against style.css before
   naming. Shares the page shell, type scale and reveal classes with index. */

/* the four steps: numbered, generous, read top to bottom */
.hw-steps { margin-top:clamp(34px,5vh,60px); display:grid; gap:0; max-width:840px; }
.hw-step { display:grid; grid-template-columns:auto 1fr; gap:clamp(18px,3vw,34px);
  padding:clamp(24px,3.4vh,34px) 0; border-top:1px solid var(--hair-2); }
.hw-step:last-child { border-bottom:1px solid var(--hair-2); }
.hw-step > b { display:grid; place-items:center; width:44px; height:44px; border-radius:100px;
  background:rgba(255,90,31,.11); border:1px solid rgba(255,90,31,.34);
  color:var(--amber); font-size:17px; font-weight:900; }
.hw-step h3 { font-size:clamp(19px,2.1vw,25px); font-weight:900; letter-spacing:-.01em;
  margin-bottom:10px; }
.hw-step p { color:var(--sub); font-size:clamp(14.5px,1.5vw,16.5px); line-height:1.95;
  font-weight:500; max-width:62ch; }

/* before / after — the comparison is the argument, so give it real weight */
.hw-ba { margin-top:clamp(30px,4.4vh,52px); display:grid; gap:clamp(18px,2.6vw,30px);
  grid-template-columns:1fr 1fr; }
.hw-col { padding:clamp(22px,3vh,30px) clamp(20px,2.6vw,30px); border-radius:18px;
  border:1px solid var(--hair-2); }
.hw-col h3 { font-size:13px; font-weight:900; letter-spacing:.14em; margin-bottom:18px; }
.hw-before { background:rgba(255,255,255,.018); }
.hw-before h3 { color:var(--sub); }
.hw-after { background:rgba(255,90,31,.05); border-color:rgba(255,90,31,.3); }
.hw-after h3 { color:var(--amber); }
.hw-col ul { list-style:none; display:grid; gap:14px; }
.hw-col li { color:var(--sub); font-size:clamp(13.5px,1.4vw,15.5px); line-height:1.8;
  font-weight:500; padding-left:20px; position:relative; }
.hw-col li::before { content:""; position:absolute; left:0; top:.72em; width:7px; height:1.5px;
  background:var(--hair-2); }
.hw-after li { color:var(--ink); }
.hw-after li::before { background:var(--amber); }

.hw-note { margin-top:clamp(22px,3vh,32px); color:var(--sub); max-width:74ch;
  font-size:clamp(13.5px,1.4vw,15.5px); line-height:1.95; font-weight:500;
  padding-left:18px; border-left:1px solid rgba(255,90,31,.4); }

/* ownership — two columns, deliberately unequal in tone */
.hw-own2 { margin-top:clamp(30px,4.4vh,52px); display:grid; gap:clamp(20px,3vw,44px);
  grid-template-columns:1fr 1fr; }
.hw-ocol h3 { font-size:clamp(17px,1.8vw,21px); font-weight:900; margin-bottom:16px; }
.hw-ocol:first-child h3 { color:var(--amber); }
.hw-ocol ul { list-style:none; display:grid; gap:12px; }
.hw-ocol li { color:var(--sub); font-size:clamp(14px,1.45vw,16px); line-height:1.8;
  font-weight:500; padding-left:22px; position:relative; }
.hw-ocol li::before { content:""; position:absolute; left:0; top:.6em; width:9px; height:9px;
  border-radius:2px; border:1.5px solid rgba(255,90,31,.5); }
.hw-ocol:last-child li::before { border-color:var(--hair-2); border-radius:100px; }
.hw-small { margin-top:20px; color:var(--sub); font-size:13.5px; line-height:1.9;
  font-weight:500; opacity:.85; }

/* next steps */
.hw-next h2 { margin-bottom:clamp(24px,3.4vh,38px); }
.hw-cards { display:grid; gap:clamp(16px,2.4vw,26px); grid-template-columns:1fr 1fr; }
.hw-card { display:block; text-decoration:none; color:inherit; border-radius:18px;
  border:1px solid var(--hair-2); padding:clamp(24px,3.2vh,34px) clamp(22px,2.8vw,32px);
  transition:border-color .4s var(--eo), background .4s var(--eo), transform .4s var(--eo); }
.hw-card h3 { font-size:clamp(19px,2vw,23px); font-weight:900; margin-bottom:12px; }
.hw-card p { color:var(--sub); font-size:clamp(13.5px,1.4vw,15.5px); line-height:1.85;
  font-weight:500; margin-bottom:18px; }
.hw-card span { color:var(--amber); font-size:14px; font-weight:800; }
@media (hover:hover) and (pointer:fine){
  .hw-card:hover { border-color:rgba(255,90,31,.5); background:rgba(255,90,31,.04);
    transform:translateY(-2px); }
}

@media (max-width:760px){
  .hw-ba, .hw-own2, .hw-cards { grid-template-columns:1fr; }
  .hw-step { grid-template-columns:auto 1fr; gap:16px; }
  .hw-step > b { width:38px; height:38px; font-size:15px; }
}

/* ── services.html + process.html ─────────────────────────────────────────
   Added 2026-08-12. sv- and pr- prefixed; all checked against style.css
   before naming (HANDOVER trap 3). */

/* the filesystem — the centrepiece of services.html. It has to look like a real
   file browser, not an infographic: every business recognises its own folders,
   and the green marks are the sales argument. */
.sv-legend { display:flex; flex-wrap:wrap; gap:12px 26px; margin-top:clamp(22px,3vh,32px); }
.sv-lg { display:inline-flex; align-items:center; gap:9px; }
.sv-lg em { font-style:normal; color:var(--sub); font-size:13px; font-weight:600; }
.sv-hl { color:var(--jade); font-weight:900; }

@media (hover:hover) and (pointer:fine){ .sv-row:hover { background:rgba(255,255,255,.028); } }

/* the slashes are the "folder inside a folder" signal — quiet, but present */
.sv-p s { text-decoration:none; color:var(--sub); opacity:.5; margin:0 5px;
  font-weight:400; }

.sv-freq { grid-column:2; justify-self:end; flex:none; font-style:normal; font-size:11px; font-weight:800;
  letter-spacing:.06em; color:var(--sub); border:1px solid var(--hair-2);
  border-radius:100px; padding:3.5px 10px; white-space:nowrap; }
.sv-auto { grid-column:3; justify-self:end; flex:none; font-style:normal; font-size:11px; font-weight:900;
  letter-spacing:.06em; color:var(--jade); background:rgba(15,203,136,.1);
  border:1px solid rgba(15,203,136,.42); border-radius:100px; padding:3.5px 10px;
  white-space:nowrap; }

@media (max-width:620px){

  /* English badges eat into the path at phone width, so they set tighter */
  html[data-lang="en"] .sv-freq,
  html[data-lang="en"] .sv-auto { font-size:10px; padding:3.5px 7px; letter-spacing:.03em; }
}

/* accounts */
.sv-acc { margin-top:clamp(28px,4vh,44px); display:grid; gap:clamp(14px,2vw,20px);
  grid-template-columns:repeat(2,1fr); }
/* the small cards get the fill and the highlight but not the blur — a dozen
   backdrop-filters is where mobile GPUs give up (the CSS banner's PERF rule) */
.sv-a { border:1px solid var(--hair-2); border-radius:14px;
  padding:clamp(18px,2.4vh,24px) clamp(16px,2vw,22px);
  background:linear-gradient(168deg, rgba(255,255,255,.055), rgba(255,255,255,.018) 60%); }
.sv-a b { display:block; font-size:clamp(15px,1.6vw,18px); font-weight:900;
  margin-bottom:8px; }
.sv-a span { color:var(--sub); font-size:clamp(13px,1.35vw,14.5px);
  line-height:1.8; font-weight:500; }

/* what comes off the desk */
.sv-jobs { margin-top:clamp(30px,4.4vh,50px); display:grid;
  gap:clamp(20px,2.8vw,34px); grid-template-columns:repeat(3,1fr); }
.sv-j h3 { font-size:clamp(15px,1.6vw,18px); font-weight:900; color:var(--amber);
  margin-bottom:14px; padding-bottom:11px; border-bottom:1px solid var(--hair-2); }
.sv-j ul { list-style:none; display:grid; gap:11px; }
.sv-j li { color:var(--sub); font-size:clamp(13px,1.35vw,14.5px); line-height:1.75;
  font-weight:500; }

/* process stages */
.pr-stages { list-style:none; margin-top:clamp(30px,4.4vh,50px); max-width:860px;
  display:grid; gap:0; }
.pr-stages > li { display:grid; grid-template-columns:auto 1fr;
  gap:clamp(16px,2.6vw,30px); padding:clamp(24px,3.4vh,34px) 0;
  border-top:1px solid var(--hair-2); }
.pr-stages > li:last-child { border-bottom:1px solid var(--hair-2); }
.pr-n { display:grid; place-items:center; width:42px; height:42px; border-radius:100px;
  background:rgba(255,90,31,.11); border:1px solid rgba(255,90,31,.34);
  color:var(--amber); font-size:16px; font-weight:900; }
.pr-b h3 { font-size:clamp(18px,2vw,24px); font-weight:900; letter-spacing:-.01em;
  margin-bottom:6px; }
.pr-when { color:var(--amber); font-size:clamp(12.5px,1.3vw,14px); font-weight:700;
  margin-bottom:12px; opacity:.9; }
.pr-b p { color:var(--sub); font-size:clamp(14px,1.45vw,16px); line-height:1.9;
  font-weight:500; max-width:60ch; }
.pr-out { margin-top:14px; padding:14px 16px; border-radius:12px;
  background:rgba(255,90,31,.05); border:1px solid rgba(255,90,31,.24); }
.pr-out b { display:block; color:var(--amber); font-size:12px; font-weight:900;
  letter-spacing:.1em; margin-bottom:6px; }
.pr-out span { color:var(--ink); font-size:clamp(13px,1.35vw,14.5px); line-height:1.8;
  font-weight:500; }

/* what we need from you */
.pr-need { margin-top:clamp(28px,4vh,44px); display:grid; gap:clamp(14px,2vw,20px);
  grid-template-columns:repeat(2,1fr); }
.pr-nd { border-left:1px solid rgba(255,90,31,.4); padding:4px 0 4px 18px; }
.pr-nd b { display:block; font-size:clamp(15px,1.6vw,17px); font-weight:900;
  margin-bottom:7px; }
.pr-nd span { color:var(--sub); font-size:clamp(13px,1.35vw,14.5px); line-height:1.8;
  font-weight:500; }

@media (max-width:860px){
  .sv-jobs { grid-template-columns:repeat(2,1fr); }
}
@media (max-width:640px){
  .sv-acc, .sv-jobs, .pr-need { grid-template-columns:1fr; }
  .sv-d2 { padding-left:30px; }
  .pr-stages > li { gap:14px; }
  .pr-n { width:36px; height:36px; font-size:14px; }
}

/* ── interactive folder map (services.html) ───────────────────────────────
   Added 2026-08-12. Colour carries meaning rather than decoration:
   jade = operational, brass = money, slate = reference-only. */

/* One column. A folder opens inside its own card, so there is no second
   column to reserve for a panel — on a phone that panel landed below all nine
   folders, off screen, and reads as "nothing happened". (2026-08-14) */
.fx { margin-top:clamp(26px,3.6vh,40px); }

/* glass, same material as the pricing panel: the sky's drifting objects stay
   visible through it as soft shapes instead of crisp doodles cutting through
   the tiles (Guto, 2026-08-14: "glassy, so you can still see the animation") */
.fx-stage { position:relative; border:1px solid var(--hair-2); border-radius:20px;
  padding:clamp(20px,2.8vh,30px) clamp(16px,2.2vw,26px) clamp(22px,3vh,32px);
  background:linear-gradient(168deg, rgba(255,255,255,.055), rgba(255,255,255,.016) 52%);
  -webkit-backdrop-filter:blur(18px) saturate(1.35); backdrop-filter:blur(18px) saturate(1.35);
  box-shadow:0 24px 60px -28px rgba(0,0,0,.75), inset 0 1px 0 rgba(255,255,255,.12); }
.fx-wires { position:absolute; inset:0; width:100%; height:100%;
  pointer-events:none; overflow:visible; }
.fx-wires path { fill:none; stroke:var(--hair-2); stroke-width:1.4; opacity:.45;
  transition:stroke .35s var(--eo), opacity .35s var(--eo); }
/* once a folder is chosen the other eight wires recede — nine equal curves at
   rest reads as clutter, not as structure */
.fx[data-on] .fx-wires path { opacity:.1; }
.fx-wires path.lit, .fx[data-on] .fx-wires path.lit { stroke:var(--amber); opacity:1; }

.fx-root { position:relative; z-index:1; display:inline-flex; align-items:baseline; gap:9px;
  padding:9px 16px; border-radius:100px; margin-bottom:clamp(22px,3vh,34px);
  background:#08120e; border:1px solid rgba(255,90,31,.42); }
.fx-root b { color:var(--amber); font-size:15px; font-weight:900; }
.fx-root em { font-style:normal; color:var(--sub); font-size:12px; font-weight:500; }
.fx-ico { font-size:12px; }

.fx-grid { position:relative; z-index:1; display:grid; gap:clamp(10px,1.5vw,16px);
  grid-template-columns:repeat(3,1fr);
  /* each card owns its height: without this the two siblings sharing a row
     with an open folder stretch into tall empty boxes */
  align-items:start; }

/* the card is the shell; the button is the folder face you press. Sitting on
   the glass stage it needs a real fill of its own, or it reads as a hole */
.fx-f { background:linear-gradient(168deg, rgba(255,255,255,.06), rgba(255,255,255,.022) 60%);
  border:1px solid var(--hair-2); border-radius:14px;
  transition:transform .22s var(--eo), border-color .22s var(--eo),
             background .22s var(--eo); }
.fx-t { display:flex; flex-direction:column; align-items:center; gap:7px; width:100%;
  padding:clamp(13px,1.8vh,17px) 8px clamp(11px,1.5vh,14px); cursor:pointer;
  background:none; border:0; color:inherit; font:inherit; text-align:center; }
.fx-fold { width:clamp(38px,4.2vw,50px); height:auto; }
.fx-back  { fill:currentColor; opacity:.34; }
.fx-front { fill:currentColor; opacity:.72; }
.fx-nm { font-size:clamp(12px,1.25vw,14px); font-weight:900; color:var(--ink);
  letter-spacing:.01em; line-height:1.35; text-align:center; }
.fx-en { font-size:9.5px; font-weight:600; color:var(--sub); letter-spacing:.08em;
  text-transform:uppercase; }
/* the two labels swap languages with the page, and 9.5px wide-tracked is a
   Latin setting: kana at that size stops being readable */
html[data-lang="en"] .fx-en { font-size:11px; letter-spacing:.02em; }

/* colour = what kind of work it is */
.fx-f[data-tone="ops"]   { color:var(--jade); }
.fx-f[data-tone="money"] { color:var(--brass); }
.fx-f[data-tone="ref"]   { color:var(--teal); }   /* filed, not automated */

/* the chevron is the affordance: these look like folders, and a folder is not
   obviously a thing you tap */
.fx-chev { width:12px; height:12px; flex:none; fill:none; stroke:currentColor;
  stroke-width:1.8; stroke-linecap:round; stroke-linejoin:round; opacity:.5;
  transition:transform .22s var(--eo), opacity .22s var(--eo); }

@media (hover:hover) and (pointer:fine){
  .fx-f:not([data-open]):hover { transform:translateY(-2px);
    border-color:rgba(255,255,255,.26); background:rgba(255,255,255,.045); }
  .fx-f:hover .fx-chev { opacity:.9; }
}
/* press feedback on the closed tile only — scaling a full-width open card
   reads as the whole section flinching */
.fx-f:not([data-open]):has(> .fx-t:active) { transform:scale(.985); }

/* Opening a folder must NOT change the grid: the card keeps its column and
   simply grows downward, pushing the rows below it (Guto, 2026-08-17). It used
   to span the full row, which threw the card you tapped across the page and
   stretched three lines of content over 1000px. Only the phone still spans —
   see the 520px block, where a column is ~139px and unusable. */
.fx-f[data-open] { border-color:currentColor; align-self:start;
  background:color-mix(in srgb, currentColor 12%, transparent); }
.fx-f[data-open] .fx-nm { font-size:clamp(13px,1.35vw,15px); }
.fx-f[data-open] .fx-back  { opacity:.6; }
.fx-f[data-open] .fx-front { opacity:1; }
.fx-f[data-open] .fx-chev  { transform:rotate(180deg); opacity:1; }

/* the disclosure itself. 0fr→1fr animates the real height without measuring
   it in JS; the inner box must own the overflow for that to work. Opening is
   the deliberate move and closing is the system responding, so closing is
   quicker. */
.fx-p { display:grid; grid-template-rows:0fr;
  transition:grid-template-rows .16s var(--eo); }
.fx-f[data-open] .fx-p { grid-template-rows:1fr; transition-duration:.24s; }
.fx-p > .fx-pi { min-height:0; overflow:hidden; }
.fx-pi { text-align:left; opacity:0; transform:translateY(6px);
  transition:opacity .16s var(--eo), transform .16s var(--eo); }
.fx-f[data-open] .fx-pi { opacity:1; transform:none; transition-delay:.05s; }
.fx-pi > :first-child { margin-top:2px; }
.fx-pi > * { padding-inline:clamp(14px,1.9vw,22px); }
.fx-pi > :last-child { padding-bottom:clamp(16px,2.2vh,22px); }

/* the hint under the grid — the folders no longer have a panel beside them to
   explain themselves, so the one line that says they open lives here */
.fx-ph { color:var(--sub); font-size:clamp(12.5px,1.3vw,14px); line-height:1.9;
  font-weight:500; text-align:center; margin-top:clamp(14px,2vh,20px); }

.fx-kids { list-style:none; display:grid; gap:8px; margin-bottom:18px;
  padding-bottom:18px; border-bottom:1px solid var(--hair-2); }
.fx-kid { display:grid; grid-template-columns:1fr auto auto; gap:9px; align-items:center;
  font-size:clamp(12.5px,1.3vw,14px); font-weight:600; color:var(--ink); }
.fx-kid s { text-decoration:none; color:var(--sub); opacity:.5; margin:0 4px; font-weight:400; }
.fx-why { color:var(--sub); font-size:clamp(13px,1.35vw,14.5px); line-height:1.95;
  font-weight:500; max-width:820px; }
.fx-why b { color:var(--ink); font-weight:800; }

@media (max-width:520px){
  .fx-grid { grid-template-columns:repeat(2,1fr); align-items:start; }
  /* a folder name is the one thing that must stay readable when the tile is
     half a phone wide */
  .fx-t { padding-inline:6px; }
  /* here the card IS the full row when open — half a phone is ~139px, and the
     badges alone need 100px of it. The header goes horizontal to match, since
     a centred label above left-aligned content reads as two separate things */
  .fx-f[data-open] { grid-column:1/-1; }
  .fx-f[data-open] .fx-t { flex-direction:row; align-items:center; gap:10px;
    text-align:left; padding:13px 14px; }
  .fx-f[data-open] .fx-fold { width:30px; }
  .fx-f[data-open] .fx-en { margin-right:auto; }
  .fx-f[data-open] .fx-chev { margin-left:auto; }
}
@media (prefers-reduced-motion:reduce){
  /* the panel still opens and closes — it just stops moving to get there */
  .fx-f, .fx-f:has(> .fx-t:active) { transition:none; transform:none; }
  .fx-p, .fx-f[data-open] .fx-p { transition:none; }
  .fx-pi { transform:none; transition:opacity .16s linear; }
  .fx-chev { transition:none; }
}
