/* ZipBar landing page
   ------------------------------------------------------------------
   Palette is lifted from the app's own artwork rather than invented:
   the deep teal of a squeezed slime and the pale mint of a relaxed
   one. The page and the product are the same two greens, so the site
   never looks bolted onto the app. */

:root{
  --ink:#0b1f1b;
  --green:#0f7a66;
  --green-deep:#0a5d4e;
  --green-dark:#083f34;
  --mint:#bdebcf;
  --mint-soft:#e8f7ee;
  --paper:#ffffff;
  --paper-2:#f4f8f5;
  --line:#dfe9e3;
  --muted:#5d7169;
  --radius:20px;
  --shadow:0 18px 48px rgba(10,60,50,.14);
  --ease-out:cubic-bezier(.16,1,.3,1);
  --ease-type:cubic-bezier(.22,1,.36,1);
}

*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{
  margin:0;
  font-family:"Pretendard Variable",Pretendard,-apple-system,system-ui,"Segoe UI","Noto Sans KR",sans-serif;
  color:var(--ink);background:var(--paper);
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
  line-height:1.6;overflow-x:hidden;
}
a{color:inherit;text-decoration:none}
img{max-width:100%;display:block}
.wrap{max-width:1120px;margin:0 auto;padding:0 24px}

/* Bands are separated by a divider only. An earlier pass also ran
   hairline rails down both sides of the content column; at this page's
   length they read as a cage around the copy rather than as structure,
   so only the horizontal rule survives. */
section + section{border-top:1px solid var(--line)}
section{padding:88px 0}

/* Small coloured tag above each heading, the reference's way of telling
   you which chapter you are in before you read the chapter. */
.sec-label{
  display:inline-block;font-size:14px;font-weight:700;letter-spacing:-.01em;
  color:var(--green);margin-bottom:14px;
}
.steps .sec-label,.hero .sec-label{color:var(--mint)}

/* Korean must break on word boundaries. The default lets the browser
   split mid-word, which turned "먹습니다" into "먹습 / 니다". */
h1,h2,h3,p,li,summary,dd,dt{word-break:keep-all;overflow-wrap:break-word}

/* `keep-all` is a Korean rule: it stops the browser splitting a word mid-
   syllable. Japanese and Chinese have no spaces at all, so the same rule
   makes a whole sentence one unbreakable run — the FAQ answers on the
   Japanese page pushed the document 48px wider than the phone. Those
   languages break between characters by default, which is correct for
   them, so the rule is lifted rather than patched. */
html[lang="ja"] :is(h1,h2,h3,p,li,summary,dd,dt),
html[lang^="zh"] :is(h1,h2,h3,p,li,summary,dd,dt){word-break:normal}
h1,h2,h3{line-height:1.18;letter-spacing:-.03em;margin:0}
h2{font-size:clamp(30px,4vw,46px);font-weight:800}
.lede{color:var(--muted);font-size:clamp(16px,1.5vw,18px);margin-top:14px}
.center{text-align:center}

.eyebrow{
  display:inline-flex;align-items:center;gap:8px;
  font-size:13px;font-weight:700;padding:7px 14px;border-radius:999px;
}
.eyebrow .dot{width:7px;height:7px;border-radius:50%;background:var(--mint)}

/* Buttons: the icon disc leads, the label follows — a frosted circle
   that goes solid on hover. */
.btn{
  display:inline-flex;align-items:center;gap:12px;
  font-weight:700;font-size:16px;padding:12px 24px 12px 12px;border-radius:999px;
  background:var(--ink);color:#fff;
  transition:transform .2s var(--ease-out),box-shadow .2s var(--ease-out);
}
.btn:hover{transform:translateY(-2px);box-shadow:var(--shadow)}
.btn .disc{
  width:36px;height:36px;border-radius:50%;display:grid;place-items:center;
  background:rgba(255,255,255,.16);backdrop-filter:blur(6px);
  transition:background .2s ease,transform .2s var(--ease-out);
}
.btn:hover .disc{background:rgba(255,255,255,.3);transform:translateX(2px)}
.btn .disc svg{width:16px;height:16px;stroke:#fff;fill:none;stroke-width:2.2;
  stroke-linecap:round;stroke-linejoin:round}
.btn.on-green{background:#fff;color:var(--green-deep)}
.btn.on-green .disc{background:rgba(15,122,102,.12)}
.btn.on-green:hover .disc{background:rgba(15,122,102,.2)}
.btn.on-green .disc svg{stroke:var(--green-deep)}

/* ── Nav ──────────────────────────────────────────────────────── */
nav{
  position:sticky;top:0;z-index:50;background:rgba(255,255,255,.86);
  backdrop-filter:saturate(180%) blur(14px);border-bottom:1px solid var(--line);
}
.nav-in{display:flex;align-items:center;gap:28px;height:66px}
.brand{display:flex;align-items:center;gap:10px;font-weight:900;font-size:19px;letter-spacing:-.02em}
.brand img{width:34px;height:auto}
.nav-links{display:flex;gap:26px;margin-left:auto;font-size:15px;font-weight:600;color:var(--muted)}
.nav-links a{position:relative;padding:2px 0}
.nav-links a::after{
  content:"";position:absolute;left:0;right:0;bottom:-2px;height:2px;
  background:var(--green);transform:scaleX(0);transform-origin:left;
  transition:transform .25s var(--ease-out);
}
.nav-links a:hover{color:var(--ink)}
.nav-links a:hover::after{transform:scaleX(1)}
.nav-cta{background:var(--green);color:#fff;font-weight:700;font-size:14px;
  padding:10px 18px;border-radius:999px;transition:background .2s ease}
.nav-cta:hover{background:var(--green-deep)}

/* Language row. Sits under the nav rather than inside it: four more items
   on a bar that already holds five would push the install button off a
   narrow screen, and the choice is a page-level one, not navigation. */
.lang-switch{
  max-width:1120px;margin:0 auto;padding:0 24px 10px;
  display:flex;gap:10px;align-items:center;flex-wrap:wrap;
  font-size:13px;color:var(--muted);
}
.lang-switch b{color:var(--ink);font-weight:700}
.lang-switch a{color:var(--muted)}
.lang-switch a:hover{color:var(--green)}

/* ── Hero ─────────────────────────────────────────────────────── */
.hero{
  background:linear-gradient(160deg,var(--green) 0%,var(--green-deep) 100%);
  color:#fff;padding:40px 0 0;position:relative;overflow:hidden;
}
.hero .eyebrow{background:rgba(255,255,255,.14);color:#fff}
.hero-mid{text-align:center;max-width:900px}
.hero-mid > *{margin-inline:auto}
/* Grid children default to `min-width:auto`, so a track sized `1fr` can
   still be pushed past its container by an item's min-content width. The
   menu bar mock is exactly that case: eleven icons that refuse to shrink
   widened the column to 384px inside a 342px stage and pushed the clock
   out of the frame. Every grid on the page gets the guard. */
.prob-grid > *,.stats > *,.bento-grid > *,.step-grid > *,.install-grid > *,
.stage > *,.stage-bars > *{min-width:0}

/* One clean headline. It used to sit on three tinted copies nudged
   down a few pixels; at Korean glyph weights those read as a blurred
   double exposure rather than depth, and they also capped the type size
   — the copies wrap on their own boxes, so any line break knocked the
   layers out of register. Without them the sentence can run large. */
.hero h1{
  font-size:clamp(30px,5.6vw,72px);font-weight:900;line-height:1.16;
  letter-spacing:-.04em;margin:26px 0 0;color:#fff;
}

.hero .sub{margin-top:22px;font-size:clamp(16px,1.7vw,19px);color:rgba(255,255,255,.86)}
.hero-cta{display:flex;align-items:center;justify-content:center;gap:18px;margin-top:24px;flex-wrap:wrap}
.hero-cta .note{font-size:14px;color:rgba(255,255,255,.72)}
.hero-trust{margin-top:18px;font-size:14px;color:rgba(255,255,255,.72);line-height:1.9}
.hero-trust b{color:#fff}

/* Menu bar mock: the product's claim, drawn to scale. */
.mock{
  background:rgba(255,255,255,.1);border:1px solid rgba(255,255,255,.2);
  border-radius:18px;padding:18px;box-shadow:0 26px 60px rgba(0,0,0,.22);
}
.mock-label{font-size:12px;font-weight:700;color:rgba(255,255,255,.7);margin-bottom:10px}
.bar{
  background:#22272b;border-radius:10px;height:30px;display:flex;align-items:center;
  justify-content:flex-end;gap:11px;padding:0 12px;
}
.bar .ico{width:15px;height:15px;border-radius:4px;background:rgba(255,255,255,.42)}
.bar .slime{height:21px;width:auto;flex:0 0 auto}
.bar .clock{margin-left:6px;font-size:11px;color:rgba(255,255,255,.72);
  font-variant-numeric:tabular-nums;flex:0 0 auto}
.bar.before{
  justify-content:flex-start;overflow:hidden;
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 62px);
  mask-image:linear-gradient(90deg,transparent 0,#000 62px);
}
.bar.before .ico:first-child{opacity:.3}
.bar.before .ico:nth-child(2){opacity:.6}
.mock-caption{font-size:13px;color:rgba(255,255,255,.72);margin-top:9px}
.mock + .mock{margin-top:16px}

/* The product shot: one wide panel under the copy rather than a column
   beside it. Before and after sit side by side so the comparison is a
   glance, not a scroll, and the mascot stands with them showing what the
   bar icon itself is doing. It bleeds off the bottom of the hero into the
   next band, which is what stops it reading as a fourth stacked card. */
.stage{
  margin-top:28px;display:grid;grid-template-columns:auto 1fr;gap:34px;
  align-items:end;padding:26px 26px 0;
  background:rgba(255,255,255,.07);border:1px solid rgba(255,255,255,.16);
  border-bottom:0;border-radius:24px 24px 0 0;
  box-shadow:0 -2px 80px rgba(0,0,0,.18);
}
.stage-bars{display:grid;grid-template-columns:1fr 1fr;gap:18px;padding-bottom:26px}
.mock + .mock{margin-top:0}

/* ── Hero mascot ──────────────────────────────────────────────
   Sized from the artwork's own aspect ratio so a re-cut sprite cannot
   silently distort it. The squash is applied to a wrapper rather than
   the <img> itself, so swapping frames mid-animation never restarts
   the deformation. */
.mascot{
  margin:0 0 26px;display:flex;flex-direction:column;align-items:center;gap:10px;
  /* Bottom-aligned with the bars so all three sit on one baseline. */
  width:clamp(150px,16vw,190px);
}
.mascot img{
  width:clamp(120px,13vw,168px);height:auto;
  transform-origin:bottom center;
  filter:drop-shadow(0 14px 26px rgba(0,0,0,.28));
}
.mascot figcaption{
  font-size:13px;font-weight:600;color:rgba(255,255,255,.78);
  font-variant-numeric:tabular-nums;
}
.mascot figcaption span{color:#fff;font-weight:800}

.feed-slime{
  appearance:none;background:transparent;border:1px solid transparent;border-radius:16px;
  color:#fff;font:inherit;cursor:pointer;display:flex;flex-direction:column;
  align-items:center;justify-content:flex-end;gap:14px;padding:10px;width:100%;min-height:174px;
}
.feed-slime span{font-size:13px;font-weight:700;text-decoration:underline;text-underline-offset:4px}
.feed-slime:hover{background:rgba(255,255,255,.08)}
.feed-slime:active{background:rgba(255,255,255,.14)}
.feed-slime:focus-visible{outline:3px solid var(--mint);outline-offset:4px}
.feed-slime:disabled{cursor:default}
.mascot #demo-hint{font-size:11px;color:rgba(255,255,255,.75);margin:0;text-align:center}
.bar .ico[hidden]{display:none}
button:focus-visible,a:focus-visible,summary:focus-visible{outline:3px solid #49a99a;outline-offset:4px}
[id]{scroll-margin-top:120px}

/* Idle breath. Deliberately slow and small: a mascot that never stops
   twitching is tiring to sit beside, which is the same reason the app
   breathes in bursts rather than continuously. */
@keyframes mascot-breathe{
  0%,100%{transform:scale(1,1)}
  50%{transform:scale(1.035,.965)}
}
.mascot img{animation:none}

/* A swallow: squash on impact, then spring back. Applied by script for
   one cycle each time the slime takes an icon. */
@keyframes mascot-gulp{
  0%{transform:scale(1,1)}
  22%{transform:scale(1.14,.86)}
  55%{transform:scale(.95,1.06)}
  100%{transform:scale(1,1)}
}
.mascot img.gulp{animation:mascot-gulp .42s cubic-bezier(.16,1,.3,1)}

/* Letting everything go: one long stretch upward. */
@keyframes mascot-release{
  0%{transform:scale(1,1)}
  30%{transform:scale(.86,1.16)}
  70%{transform:scale(1.06,.96)}
  100%{transform:scale(1,1)}
}
.mascot img.release{animation:mascot-release .6s cubic-bezier(.16,1,.3,1)}

@media (prefers-reduced-motion:reduce){
  .mascot img{animation:none!important}
}

/* ── Marquee ──────────────────────────────────────────────────── */
@keyframes marquee-scroll{from{transform:translateX(0)}to{transform:translateX(-50%)}}

/* ══ Showcase ═══════════════════════════════════════════════════
   The one section on the page that is graphic rather than typographic:
   hard-edged squares, a light heading, and cards that react to the
   pointer. It earns the attention because it is where the product is
   actually shown.
   ═══════════════════════════════════════════════════════════════ */
.showcase{position:relative;overflow:hidden;padding:112px 0 88px}

/* Floating squares. The element carries the scroll parallax that script
   writes into --py; the ::before carries the idle bob. Splitting them
   matters — one element cannot hold two competing transforms. */
.float-layer{position:absolute;inset:0;pointer-events:none;overflow:hidden;z-index:0}
.floater{position:absolute;transform:translateY(var(--py,0px));will-change:transform}
.floater::before{
  content:'';position:absolute;inset:0;background:var(--ink);opacity:.82;
  animation:bob var(--bob,3s) ease-in-out var(--bob-delay,0s) infinite;
}
@keyframes bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-10px)}}

.showcase .wrap{position:relative;z-index:1}
.badge{
  display:inline-block;margin-bottom:20px;padding:6px 16px;
  background:var(--ink);color:#fff;font-size:13px;font-weight:500;letter-spacing:.02em;
}
/* Light where the rest of the page is heavy, and the second half greyed
   back so the eye reads the subject first. */
h2.display{
  font-size:clamp(29px,3.4vw,46px);font-weight:300;line-height:1.25;
  letter-spacing:-.03em;margin:0;
}
h2.display .dim{color:rgba(11,31,27,.38)}

/* ── Case cards ──────────────────────────────────────────────── */
.case-grid{display:grid;gap:16px;grid-template-columns:1fr 1fr;margin-top:52px}
.case-grid > *{min-width:0}
.case{
  position:relative;aspect-ratio:4/3;overflow:hidden;border-radius:16px;
  background:linear-gradient(150deg,var(--green) 0%,var(--green-deep) 100%);
}
.case-art{position:absolute;inset:0;display:grid;place-items:center}
.case-art img{width:44%;max-width:210px;filter:drop-shadow(0 18px 32px rgba(0,0,0,.3))}

/* Pixel wipe. Ninety-six blocks per card, scaled in on a diagonal
   stagger and out on the opposite diagonal, so the card dissolves in
   one direction and resolves in the other instead of blinking. */
.pixels{position:absolute;inset:0;z-index:5;pointer-events:none}
.px{
  position:absolute;background:var(--ink);
  transform:scale(0);opacity:0;transform-origin:center;
  transition:transform .25s var(--ease-type),opacity .25s var(--ease-type);
  transition-delay:var(--dout,0s);
}
.case:hover .px,.case:focus-within .px{
  transform:scale(1);opacity:1;transition-delay:var(--din,0s);
}
/* Centred rather than pinned to the top: once the wipe has taken the
   artwork away the sentence is the only thing left on the card, and a
   line of text hanging off the top edge left the middle empty. */
.case-detail{
  position:absolute;z-index:6;inset:0;margin:0;
  display:flex;align-items:center;
  padding:0 30px 46px;color:#fff;
  font-size:clamp(16px,1.5vw,19px);font-weight:500;line-height:1.65;letter-spacing:-.02em;
  opacity:0;transform:translateY(8px);
  transition:opacity .3s var(--ease-out),transform .3s var(--ease-out);
}
.case:hover .case-detail,.case:focus-within .case-detail{
  opacity:1;transform:none;transition-delay:.26s;
}

/* Magnetic squares: script writes the offset, the transition does the
   settling. A real spring would need a frame loop per square; at this
   size the difference is not visible and the loop is not worth it. */
.mag{
  position:absolute;z-index:7;background:var(--ink);pointer-events:none;
  transform:translate(var(--dx,0px),var(--dy,0px));
  transition:transform .55s var(--ease-out);
}
.plus{
  position:absolute;z-index:10;right:16px;top:16px;
  width:28px;height:28px;display:flex;align-items:center;justify-content:center;
  border:1px solid rgba(255,255,255,.34);color:#fff;font-size:13px;line-height:1;
}
.plus.dark{position:static;border-color:rgba(11,31,27,.2);color:var(--ink);margin-bottom:16px}
.plate{
  position:absolute;z-index:20;left:0;bottom:0;max-width:74%;
  background:var(--paper);padding:10px 18px 12px;border-radius:0 16px 0 0;
}
.plate h3{margin:0;font-size:clamp(20px,2.1vw,30px);font-weight:500;line-height:1.15;letter-spacing:-.03em}
.plate-meta{display:flex;gap:16px;margin-top:6px;align-items:baseline}
.plate-meta .cat{font-size:12px;color:var(--muted)}
.plate-meta .num{font-size:12px;font-weight:700;color:var(--ink);font-variant-numeric:tabular-nums}

/* ── Closing row: the ask, and the ticker ────────────────────── */
.close-row{display:flex;gap:48px;align-items:flex-end;margin-top:64px}
.close-copy{max-width:440px}
.close-copy p{margin:0;font-size:14px;line-height:1.75;color:var(--muted)}
/* The ask sits above the install button, not beside it: side by side they
   compete, and the install is what the visitor came for. */
.star-cta{
  /* `flex` with a fitted width, not `inline-flex`: inline put it on the same
     line as the install button and the two overlapped. */
  display:flex;width:fit-content;align-items:center;gap:8px;margin-top:22px;
  padding:9px 15px;border:1px solid rgba(11,31,27,.16);border-radius:999px;
  font-size:14px;font-weight:600;color:var(--ink);
  transition:background .2s,border-color .2s;
}
.star-cta svg{color:#f5c518}
.star-cta:hover{background:rgba(245,197,24,.14);border-color:rgba(245,197,24,.5)}
.close-copy .cta-arrow{margin-top:14px}

.cta-arrow{display:inline-flex;align-items:flex-end;margin-top:26px}
.cta-label{
  display:inline-flex;align-items:center;padding:11px 18px;
  background:var(--ink);color:#fff;font-size:16px;font-weight:600;
  transition:background .2s;
}
.cta-arrow:hover .cta-label{background:rgba(11,31,27,.85)}
.cta-badge{
  width:26px;height:26px;display:flex;align-items:center;justify-content:center;
  background:var(--ink);color:#fff;margin-bottom:24px;
  transition:margin-bottom .3s var(--ease-type);
}
.cta-arrow:hover .cta-badge{margin-bottom:38px}

.close-marquee{flex:1;overflow:hidden;padding:18px 0;min-width:0}
/* The track holds two identical halves — script duplicates them — so a
   scroll to -50% lands exactly where it started. `w-max` is what keeps
   the halves from wrapping and breaking that. */
.marquee-track{
  display:flex;width:max-content;white-space:nowrap;
  animation:marquee-scroll 28s linear infinite;
}
.close-marquee:hover .marquee-track{animation-play-state:paused}
.logo{
  flex:0 0 auto;display:inline-flex;align-items:center;gap:10px;padding:0 32px;
  font-size:14px;font-weight:600;letter-spacing:.01em;color:rgba(11,31,27,.8);
  white-space:nowrap;
}
.logo svg{flex:0 0 auto;color:var(--ink)}

/* No pointer, no hover — so the sentence the wipe reveals would never
   be seen on a phone. There it simply stands on the card, and the wipe
   that had nothing to trigger it is removed rather than left dormant. */
@media (hover:none){
  .pixels{display:none}
  .case-detail{
    opacity:1;transform:none;align-items:flex-start;
    padding:22px 22px 0;font-size:14px;font-weight:500;
    text-shadow:0 1px 14px rgba(6,40,33,.55);
  }
  .case-art{place-items:end center;padding-bottom:14%}
  .case-art img{width:38%}
}

@media (max-width:900px){
  .showcase{padding:76px 0 64px}
  .case-grid{grid-template-columns:1fr}
  .close-row{flex-direction:column;align-items:stretch;gap:26px}
  .close-marquee{border-top:1px solid var(--line)}
  .float-layer{display:none}
}

/* ── Problem ──────────────────────────────────────────────────── */
/* Bands used to alternate paper / paper-2 / green. The rails and
   dividers carry the sectioning now, so the middle of the page is one
   continuous sheet and only the two ends are filled with colour. */
.problem{background:var(--paper)}
.problem h2 .hl{color:var(--green)}
.prob-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;margin-top:44px}
.prob{background:#fff;border:1px solid var(--line);border-radius:var(--radius);padding:26px;
  transition:transform .25s var(--ease-out),box-shadow .25s var(--ease-out)}
.prob:hover{transform:translateY(-4px);box-shadow:var(--shadow)}
.prob .emo{font-size:26px}
.prob h3{font-size:17px;font-weight:800;margin-top:12px}
.prob p{color:var(--muted);font-size:15px;margin:8px 0 0}

/* ── Stats ────────────────────────────────────────────────────── */
.stats{display:grid;grid-template-columns:repeat(3,1fr);gap:22px;margin-top:12px}
.stat{background:var(--mint-soft);border:1px solid var(--mint);
  border-radius:var(--radius);padding:30px;text-align:center}
.stat .n{font-size:clamp(30px,3.6vw,44px);font-weight:900;color:var(--green-deep);
  letter-spacing:-.035em;font-variant-numeric:tabular-nums}
.stat .l{font-size:14px;color:var(--muted);margin-top:6px}
.stats-note{margin-top:18px;font-size:14px;color:var(--muted);text-align:center}

/* ── Bento mosaic ─────────────────────────────────────────────── */
.bento{background:var(--paper)}
.bento-grid{
  display:grid;grid-template-columns:repeat(3,1fr);gap:18px;margin-top:44px;
}
.tile{
  border-radius:var(--radius);padding:28px;position:relative;overflow:hidden;
  border:1px solid var(--line);background:#fff;
  transition:transform .25s var(--ease-out),box-shadow .25s var(--ease-out);
}
.tile:hover{transform:translateY(-4px);box-shadow:var(--shadow)}
.tile h3{font-size:18px;font-weight:800}
.tile p{color:var(--muted);font-size:15px;margin:9px 0 0}
.tile img{width:46px;margin-bottom:14px}

/* The wide tile carries the scale demo, so it spans the full row. */
.tile.wide{grid-column:1 / -1;background:linear-gradient(135deg,#fff 0%,var(--mint-soft) 100%)}
.scale-row{display:flex;align-items:flex-end;justify-content:center;
  gap:clamp(16px,4vw,46px);margin-top:26px;flex-wrap:wrap}
.scale-item{text-align:center}
.scale-item img{width:72px;margin:0 auto 0}
.scale-item .cap{margin-top:12px;font-size:14px;font-weight:700}
.scale-item .sub{font-size:13px;color:var(--muted)}

.tile.dark{background:linear-gradient(150deg,var(--green) 0%,var(--green-deep) 100%);
  color:#fff;border-color:transparent}
.tile.dark p{color:rgba(255,255,255,.82)}

/* ── Steps ────────────────────────────────────────────────────── */
.steps{background:var(--green-deep);color:#fff}
.steps .lede{color:rgba(255,255,255,.8)}
.steps .eyebrow{background:rgba(255,255,255,.14);color:#fff}
.step-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:22px;margin-top:44px}
.step{background:rgba(255,255,255,.1);border:1px solid rgba(255,255,255,.2);
  border-radius:var(--radius);padding:28px}
.step .n{font-size:13px;font-weight:900;color:var(--mint);letter-spacing:.08em}
.step h3{font-size:18px;font-weight:800;margin-top:10px}
.step p{color:rgba(255,255,255,.82);font-size:15px;margin:9px 0 0}

/* ── Install ──────────────────────────────────────────────────── */
.install-grid{display:grid;grid-template-columns:1fr 1fr;gap:26px;margin-top:44px;align-items:start}
.download-note{font-size:14px;color:var(--muted);margin:14px 0 20px}
.install-checklist{padding-left:24px;margin-top:24px}
.install-checklist li{padding-left:6px;margin:16px 0;font-size:16px}
.install-checklist li::marker{color:var(--green);font-weight:800}
.help-link{color:var(--green-deep);text-decoration:underline;text-underline-offset:3px}
.install-advanced{margin-top:32px}
.install-advanced pre{margin-top:16px}
.share-intro{margin:34px auto 0;max-width:520px;font-size:14px}
.share-link{background:transparent;border:1px solid rgba(255,255,255,.65);border-radius:10px;
  color:#fff;font:inherit;font-weight:600;padding:11px 18px;cursor:pointer}
.share-link:hover,.share-link:active{background:rgba(255,255,255,.1)}
.share-status{min-height:1.6em;margin:10px 0 0;color:var(--mint)}
.share-fallback{width:100%;font:inherit;padding:10px;border-radius:8px;border:1px solid var(--mint)}
/* Soft-wrapped rather than side-scrolled. The install command is one
   long URL; a horizontal scrollbar hides half of it, and a backslash
   continuation is one careless copy away from a broken command. */
pre{background:#0d211d;color:#d6f2e6;border-radius:16px;padding:22px;
  font-size:14px;line-height:1.85;margin:0;
  white-space:pre-wrap;word-break:break-all;
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
pre .c{color:#7fae9f}
.req{border:1px solid var(--line);border-radius:var(--radius);padding:24px}
.req h3{font-size:16px;font-weight:800;margin-bottom:12px}
.req dl{margin:0;display:grid;grid-template-columns:auto 1fr;gap:9px 16px;font-size:15px}
.req dt{color:var(--muted)}
.req dd{margin:0;font-weight:600}
.callout{margin-top:22px;background:var(--mint-soft);border:1px solid var(--mint);
  border-radius:var(--radius);padding:20px 22px;font-size:15px}
.callout b{color:var(--green-deep)}
.callout a{color:var(--green-deep);font-weight:700;text-decoration:underline}
/* `brew install --cask aisyncclub/slimezip/slimezip` is 376px unbroken, wider
   than a 375pt iPhone. Nothing in the default breaking rules is guaranteed to
   split it, so say it explicitly rather than hope the engine breaks on a
   slash. */
.callout code{overflow-wrap:anywhere}

/* ── FAQ ──────────────────────────────────────────────────────── */
.faq{background:var(--paper)}
.faq-list{max-width:820px;margin:40px auto 0}
details{background:#fff;border:1px solid var(--line);border-radius:16px;
  padding:20px 22px;margin-top:12px}
summary{cursor:pointer;font-weight:700;font-size:16px;list-style:none;
  display:flex;justify-content:space-between;align-items:center;gap:16px}
summary::-webkit-details-marker{display:none}
summary::after{content:"+";color:var(--green);font-weight:900;font-size:20px;
  transition:transform .2s var(--ease-out)}
details[open] summary::after{content:"−"}
details p{color:var(--muted);font-size:15px;margin:12px 0 0}

/* ── Final CTA ────────────────────────────────────────────────── */
.final{background:linear-gradient(160deg,var(--green-deep) 0%,var(--green-dark) 100%);
  color:#fff;text-align:center}
.final img{width:96px;margin:0 auto 22px}
.final .lede{color:rgba(255,255,255,.82)}
.final .btn{margin-top:30px}

/* ── Footer ───────────────────────────────────────────────────── */
/* Bold lead, quiet tail. The lead carries the whole point so the tail
   can drop back — but only on the light sheet: setting it here without
   scoping once turned the step copy grey on green, which is nearly
   invisible. Each dark surface names its own pair. */
.prob p b,.tile p b,.step p b,.mock-caption b{font-weight:800}
.prob p,.tile p{color:var(--muted)}
.prob p b,.tile p b{color:var(--ink)}
.tile.dark p b,.steps .step p b,.mock-caption b{color:#fff}

footer{background:#08201b;color:rgba(255,255,255,.62);padding:52px 0;font-size:14px}
.foot-top{display:flex;gap:36px;flex-wrap:wrap;align-items:flex-start}
.foot-brand{display:flex;align-items:center;gap:10px;color:#fff;font-weight:900;font-size:17px}
.foot-brand img{width:30px}
.foot-links{display:flex;gap:22px;margin-left:auto;flex-wrap:wrap}
.foot-links a:hover{color:#fff}
.foot-note{margin-top:26px;padding-top:22px;border-top:1px solid rgba(255,255,255,.12);line-height:1.9}

/* ── Responsive ───────────────────────────────────────────────── */
@media (max-width:900px){
  section{padding:72px 0}
  .install-grid{grid-template-columns:1fr}
  .prob-grid,.step-grid,.stats{grid-template-columns:1fr}
  .bento-grid{grid-template-columns:1fr}
  .nav-links{display:none}
  .lang-switch{font-size:12px;gap:8px}
  /* The stage turns into a single column: two menu bars side by side
     inside a 390px screen would be two illegible slivers. */
  .stage{grid-template-columns:1fr;gap:22px;padding:22px 18px 0;align-items:center}
  .stage-bars{grid-template-columns:1fr;padding-bottom:22px}

  /* The hard breaks are typeset for a wide column. On a phone they
     land mid-thought and leave a two-word orphan line, so let the
     text wrap on its own instead. */
  .sub br,.hero-trust br{display:none}
}

/* ══════════════════════════════════════════════════════════════
   Entrance choreography
   ──────────────────────────────────────────────────────────────
   One shot, then gone. A boot script marks the document
   `motion-pending` before first paint so nothing flashes in at its
   final position; the runner swaps that for `entrance-run`, and
   after the last delay finishes it removes the class entirely so
   the page settles back to its plain authored styles. Keeping the
   animation classes on forever would leave `will-change` hints and
   compositor layers alive for the whole session.

   Everything here is inert under `prefers-reduced-motion` — the
   boot script never adds the class in that case, so these rules
   simply never match.
   ══════════════════════════════════════════════════════════════ */

.motion-pending .anim{opacity:0;visibility:hidden}

.entrance-run .anim{will-change:opacity,transform;animation-fill-mode:backwards}

@keyframes panel-settle{
  from{opacity:0;transform:translateY(12px) scale(.988);
       clip-path:inset(3% round 22px)}
  62%{opacity:1}
  to{opacity:1;transform:none;clip-path:inset(0 round 22px)}
}
@keyframes type-unmask{
  from{opacity:0;transform:translateY(16px);clip-path:inset(0 0 96% 0)}
  to{opacity:1;transform:none;clip-path:inset(0 0 0 0)}
}
@keyframes content-rise{
  from{opacity:0;transform:translateY(9px)}
  to{opacity:1;transform:none}
}
@keyframes interface-settle{
  from{opacity:0;transform:translateY(16px) scale(.975)}
  to{opacity:1;transform:none}
}
@keyframes detail-settle{
  from{opacity:0;transform:translateY(8px) scale(.97)}
  to{opacity:1;transform:none}
}

/* The hero leads; the mock resolves; the trust line lands last. */
.entrance-run .a-h1{animation:type-unmask .82s var(--ease-type) .06s}
.entrance-run .a-eyebrow{animation:content-rise .5s var(--ease-out) 0s}
.entrance-run .a-sub{animation:content-rise .56s var(--ease-out) .40s}
.entrance-run .a-cta{animation:content-rise .54s var(--ease-out) .54s}
.entrance-run .a-trust{animation:content-rise .5s var(--ease-out) .68s}
.entrance-run .a-mock1{animation:interface-settle .84s var(--ease-out) .34s}
.entrance-run .a-mock2{animation:interface-settle .92s var(--ease-out) .46s}
.entrance-run .a-mascot{animation:detail-settle .7s var(--ease-out) .72s}

/* Stacked headline layers keep their own offset while dropping in,
   which is why they animate a custom property instead of plain Y. */

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation:none!important;transition:none!important}
  html{scroll-behavior:auto}
  .marquee-track{animation:none!important}
  .motion-pending .anim{opacity:1;visibility:visible}
}

/* ── Scroll reveal (everything below the fold) ────────────────── */
.reveal{opacity:0;transform:translateY(18px);
  transition:opacity .7s var(--ease-out),transform .7s var(--ease-out)}
.reveal.in{opacity:1;transform:none}
/* Children stagger off the same observer, so a grid resolves left to
   right instead of all at once. */
.reveal[data-stagger] > *{opacity:0;transform:translateY(14px);
  transition:opacity .6s var(--ease-out),transform .6s var(--ease-out)}
.reveal[data-stagger].in > *{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){
  .reveal,.reveal[data-stagger] > *{opacity:1!important;transform:none!important}
}

/* The slime breathes here as it does in the menu bar: rarely, and
   only where a person is already looking. */
@keyframes breathe{
  0%,100%{transform:scaleX(1) scaleY(1)}
  50%{transform:scaleX(1.05) scaleY(.95)}
}
.breathe{animation:breathe 3.4s ease-in-out infinite;transform-origin:bottom center}
@media (prefers-reduced-motion:reduce){.breathe{animation:none}}


/* ── 실제 녹화 ──────────────────────────────────────────────────
   The GIF is 900x26 — a menu bar is a sliver, and cropping it to
   anything squarer would mean cropping out the icons that vanish,
   which is the whole point. So the frame leans into the shape: full
   width on a dark band, with the bar's own wallpaper showing.
   ─────────────────────────────────────────────────────────────── */
.demo-strip{background:var(--green-dark);color:#fff;padding:64px 0 72px}
.demo-strip .badge{background:rgba(255,255,255,.12);color:var(--mint)}
.demo-strip h2{color:#fff;margin-bottom:34px}
.demo-shot{margin:0}
.demo-shot img{display:block;width:100%;max-width:900px;height:auto;margin:0 auto;
  border-radius:10px;box-shadow:0 18px 46px rgba(0,0,0,.42);
  /* The capture is 1x; letting it scale up past its own width only
     blurs it, so it stops at 900 and the band absorbs the rest. */
  image-rendering:auto}
.demo-shot figcaption{margin-top:22px;font-size:15px;color:rgba(255,255,255,.72);
  max-width:620px;margin-inline:auto;line-height:1.6}
.demo-shot figcaption b{color:var(--mint)}
