/* ==========================================================================
   3dlogogif — infinite-loop one-pager
   Structure, layout and visual language follow redis.agency/en:
   black ground, centred high-contrast serif, white pill chrome, floating 3D.
   ========================================================================== */

:root{
  --bg:#fff;
  --ink:#000;
  --ink-60:rgba(0,0,0,.6);
  --ink-42:rgba(0,0,0,.42);
  --line:rgba(0,0,0,.18);
  --blue:#1e86e2;

  --pad:clamp(16px,2.6vw,36px);
  --hdr-h:92px;

  --ease:cubic-bezier(.22,.61,.36,1);
  --ease-io:cubic-bezier(.16,1,.3,1);

  /* Lato, self-hosted and inlined in lato.css so it also resolves from disk */
  --display:'Lato',-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif;
  --sans:Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif;

  --col:min(586px,84vw);   /* the centred content column */
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;
  background:var(--bg);
  color:var(--ink);
  font-family:var(--sans);
  font-size:16px;
  line-height:1.5;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  overflow-x:hidden;
}
img,canvas,svg{display:block;max-width:100%}
h1,h2,h3,p,ul,figure{margin:0}
ul{padding:0;list-style:none}
a{color:inherit;text-decoration:none}
::selection{background:#000;color:#fff}
:focus-visible{outline:2px solid #000;outline-offset:4px;border-radius:4px}

.wrap{
  width:100%;
  padding-inline:var(--pad);
  display:flex;flex-direction:column;align-items:center;
  text-align:center;
}
.sec{
  position:relative;
  padding-block:clamp(80px,11vh,150px);
}

/* ==========================================================================
   page backdrop — the loading screen's image, held back to 30% so it reads as
   a tint under the content rather than a picture behind it. Fixed, so it does
   not travel with the loop.
   ========================================================================== */
body::before{
  content:"";
  position:fixed;inset:0;z-index:0;
  background:url("../img/loading%20screen%20bg.jpg") center/cover no-repeat;
  opacity:.3;
  pointer-events:none;
}

/* ==========================================================================
   the mark
   ========================================================================== */
.mark{width:28px;height:32px;overflow:visible}
.mark--lg{width:46px;height:52px}
.mark__glyph{fill:#000}

/* ==========================================================================
   pills — the whole navigation is white capsules in the corners
   ========================================================================== */
.pill{
  display:inline-flex;align-items:center;justify-content:center;
  height:46px;padding-inline:22px;
  border-radius:99px;
  background:#000;color:#fff;
  font-size:.95rem;line-height:1;letter-spacing:-.01em;
  white-space:nowrap;
  transition:transform .4s var(--ease-io),background-color .3s var(--ease),color .3s var(--ease);
}
.pill:hover,.pill:focus-visible{transform:translateY(-2px);background:#2b2b2b}
.pill--lg{height:58px;padding-inline:34px;font-size:1.05rem}
.pill.is-active{background:#4a4a4a}

/* the header reads as plain text — the capsules are for calls to action */
.navlink{
  display:inline-flex;align-items:center;
  height:46px;
  color:var(--ink);
  font-size:.95rem;line-height:1;letter-spacing:-.01em;
  white-space:nowrap;
  transition:opacity .3s var(--ease);
}
.navlink:hover,.navlink:focus-visible{opacity:.55}

/* Generator: a hairline button with a blue glow travelling round it. The angle
   is a registered property so the conic gradient can actually be animated —
   without @property it is not an interpolable value and the glow sits still,
   which is the graceful way for this to fail. */
@property --navcta-a{syntax:'<angle>';initial-value:0deg;inherits:false}
.navcta{
  position:relative;isolation:isolate;
  height:40px;padding-inline:20px;
  border:1px solid var(--ink);
  border-radius:99px;
  background:transparent;
  transition:background-color .35s var(--ease),color .35s var(--ease),
             border-color .35s var(--ease);
}
.navcta::before{
  content:"";
  position:absolute;inset:-4px;
  border-radius:inherit;
  z-index:-1;                 /* held inside the button by `isolation` */
  background:conic-gradient(from var(--navcta-a),
    transparent 0deg,var(--blue) 42deg,transparent 118deg,transparent 360deg);
  filter:blur(7px);
  opacity:.2;
  animation:navctaOrbit 4.2s linear infinite;
}
@keyframes navctaOrbit{to{--navcta-a:360deg}}
.navcta:hover,.navcta:focus-visible{
  background:var(--blue);border-color:var(--blue);color:#fff;opacity:1;
}

/* language switcher — closed it is just the current code under a hairline.
   A <details> rather than a scripted menu so it still opens with JavaScript
   off, and so the keyboard gets the open/close for free. */
.lang{position:relative;display:inline-flex}
.lang__now{
  display:inline-flex;align-items:center;
  height:46px;
  color:var(--ink);
  font-size:.95rem;line-height:1;letter-spacing:.02em;
  cursor:pointer;
  list-style:none;                 /* the disclosure triangle, in Firefox */
  transition:opacity .3s var(--ease);
}
.lang__now::-webkit-details-marker{display:none}
.lang__now::marker{content:""}
.lang__now span{
  /* the rule hugs the text rather than the 46px hit area */
  border-bottom:1px solid currentColor;
  padding-bottom:2px;
}
.lang__now:hover,.lang:focus-within .lang__now{opacity:.55}
.lang__menu{
  position:absolute;top:calc(100% - 6px);right:0;
  min-width:132px;
  display:grid;gap:2px;
  margin:0;padding:8px;
  list-style:none;
  background:#fff;
  border-radius:14px;
  box-shadow:0 10px 34px rgba(0,0,0,.13);
}
.lang__opt{
  display:block;
  padding:7px 12px;
  border-radius:9px;
  font-size:.88rem;line-height:1.2;
  color:var(--ink);
  white-space:nowrap;
  transition:background-color .2s var(--ease);
}
.lang__opt:hover,.lang__opt:focus-visible{background:rgba(0,0,0,.05)}
.lang__opt[aria-current]{font-weight:600}

/* mobile menu — hidden until the header runs out of room for the full row.
   A <details> like the switcher, so it opens with JavaScript off and the
   keyboard gets it for free. */
.menu{display:none;position:relative}
.menu__btn{
  display:flex;flex-direction:column;justify-content:center;
  gap:5px;width:24px;height:34px;
  cursor:pointer;
  list-style:none;                 /* the disclosure triangle, in Firefox */
}
.menu__btn::-webkit-details-marker{display:none}
.menu__btn::marker{content:""}
.menu__btn span{
  display:block;height:2px;width:100%;
  background:var(--ink);border-radius:2px;
  transition:transform .28s var(--ease),opacity .18s var(--ease);
}
/* the bars are 2px with 5px between them, so the outer two are exactly 7px
   off centre — that is the distance each has to travel to make the cross */
.menu[open] .menu__btn span:nth-child(1){transform:translateY(7px) rotate(45deg)}
.menu[open] .menu__btn span:nth-child(2){opacity:0}
.menu[open] .menu__btn span:nth-child(3){transform:translateY(-7px) rotate(-45deg)}
.menu__panel{
  position:absolute;top:calc(100% - 4px);left:0;
  min-width:176px;
  display:grid;gap:2px;
  padding:8px;
  background:#fff;
  border-radius:14px;
  box-shadow:0 10px 34px rgba(0,0,0,.13);
}
.menu__link{
  display:block;
  padding:9px 14px;
  border-radius:9px;
  font-size:.92rem;line-height:1.2;letter-spacing:.01em;
  color:var(--ink);
  white-space:nowrap;
  transition:background-color .2s var(--ease);
}
.menu__link:hover,.menu__link:focus-visible{background:rgba(0,0,0,.05)}
.menu__link--cta{font-weight:600;color:var(--blue)}

/* ==========================================================================
   preloader — the mark alone on the supplied backdrop
   ========================================================================== */
.preloader{
  position:fixed;inset:0;z-index:200;
  display:grid;place-items:center;
  background:var(--bg) url("../img/loading%20screen%20bg.jpg") center/cover no-repeat;
  transition:opacity .8s var(--ease),visibility .8s;
}
.preloader.is-done{opacity:0;visibility:hidden;pointer-events:none}
.preloader .mark{animation:markIn 2.2s var(--ease-io) infinite}
@keyframes markIn{0%,100%{transform:scale(1);opacity:.85}50%{transform:scale(1.07);opacity:1}}

/* ==========================================================================
   3D stage
   ========================================================================== */
.stage{
  position:fixed;inset:0;pointer-events:none;
  opacity:0;transition:opacity 1.2s var(--ease-io);
}
/* the water and the object share one layer, in front of the page content and
   below the pills, so the waves wash over the type */
.stage{z-index:20}
body.is-3d-ready .stage{opacity:1}
html.no-js .stage{opacity:1}

/* ==========================================================================
   fixed header
   ========================================================================== */
.hdr{
  position:fixed;top:0;left:0;right:0;z-index:60;
  height:var(--hdr-h);
  /* centred rather than spread: the links sit either side of the mark, not
     out at the edges of the page */
  display:flex;align-items:center;justify-content:center;
  gap:clamp(16px,2.6vw,40px);
  padding-inline:var(--pad);
  pointer-events:none;
}
.hdr > *{pointer-events:auto}
.hdr__side{display:flex;align-items:center;gap:clamp(19.5px,2.55vw,39px)}
.hdr__mark{display:grid;place-items:center}

/* ==========================================================================
   looping viewport
   ========================================================================== */
.viewport{display:block;position:relative;z-index:10}
html.js-loop .viewport{
  position:fixed;inset:0;z-index:10;
  overflow:hidden;
}
html.js-loop .track{will-change:transform;backface-visibility:hidden}
html.js-loop body{overflow:hidden;height:100%}

/* ==========================================================================
   hero — one enormous centred serif lockup
   ========================================================================== */
.sec--hero{
  min-height:100svh;
  display:grid;place-items:center;align-content:center;
  padding-block:var(--hdr-h);
}
.hero__title{
  font-family:var(--display);
  font-weight:900;
  letter-spacing:-.045em;
  font-size:clamp(3.9rem,17vw,15.5rem);
  line-height:.9;
  text-align:center;
}
.hero__title span{display:block}

/* ==========================================================================
   statement
   ========================================================================== */
.statement{
  font-family:var(--display);
  font-weight:300;
  font-size:clamp(2.1rem,5.8vw,4.6rem);
  line-height:1.02;
  letter-spacing:-.015em;
  text-align:center;
  max-width:100%;
}
.statement span{display:block}

.lede{
  margin-top:clamp(28px,4vh,54px);
  max-width:var(--col);
  font-size:clamp(1rem,1.35vw,1.22rem);
  line-height:1.42;
  color:var(--ink);
  text-align:center;
}

/* ==========================================================================
   example strip — the same drifting row, carrying clips instead of words
   ========================================================================== */
.sec--examples{padding-block:clamp(50px,8vh,110px)}
.marquee{overflow:hidden}
.marquee__row{
  display:flex;align-items:center;gap:clamp(48px,7vw,120px);
  width:max-content;
  font-family:var(--sans);
  font-size:clamp(2.2rem,4.6vw,3.9rem);
  font-weight:800;
  font-style:italic;
  letter-spacing:-.045em;
  white-space:nowrap;
  will-change:transform;
}
/* clips need their own rhythm: tighter gaps than the display type had */
.marquee__row--media{gap:clamp(14px,1.8vw,26px)}
.ex{
  /* 9:16, the format the clips were made in — sized by height so the strip
     keeps a steady band whatever the viewport does */
  height:clamp(312px,45.6vh,528px);
  aspect-ratio:9/16;
  width:auto;
  flex:0 0 auto;
  object-fit:cover;
  border-radius:18px;
  background:var(--line);   /* the tile holds its shape before the clip lands */
  display:block;
}

/* ==========================================================================
   section titles + service-style rows
   ========================================================================== */
.title{
  font-family:var(--display);
  font-weight:300;
  font-size:clamp(2.8rem,7.4vw,5.9rem);
  line-height:1;
  letter-spacing:-.015em;
  margin-bottom:clamp(48px,8vh,110px);
}
.rows{width:var(--col);text-align:left}
.row{
  display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,1.05fr);
  gap:clamp(16px,3vw,42px);
  padding-block:clamp(26px,4vh,44px);
  border-top:1px solid var(--line);
}
.row:last-child{border-bottom:1px solid var(--line)}
.row__name{
  font-family:var(--display);
  font-weight:400;
  font-size:clamp(1.35rem,2.2vw,1.9rem);
  line-height:1.12;
  letter-spacing:-.01em;
}
.row__list{display:grid;gap:clamp(12px,1.6vh,20px);align-content:start}
.row__list li{
  position:relative;
  padding-left:26px;
  font-size:clamp(.94rem,1.1vw,1.05rem);
  line-height:1.38;
  color:var(--ink-60);
}
.row__list li::before{
  content:"\2014";
  position:absolute;left:0;top:0;
  color:var(--ink-42);
}
.row__copy{
  font-size:clamp(.94rem,1.1vw,1.05rem);
  line-height:1.5;
  color:var(--ink-60);
}

/* ==========================================================================
   material line — a fixed rule the object descends through, splitting it into
   the finish above and the finish below
   ========================================================================== */
.sec--materials{
  /* nothing but an anchor: the sweep is measured from here and plays over the
     ordinary content, so the section takes no room of its own */
  min-height:0;
  padding-block:0;
}
.matlines{position:fixed;inset:0;z-index:30;pointer-events:none}
.matline{
  /* placed by the scene each frame: the rules live in page space, 900px
     apart, and sweep up past the object as you scroll. translateY(-50%) puts
     the rule itself — drawn at this element's middle — on that mark. */
  position:absolute;left:0;right:0;top:0;
  display:flex;align-items:center;justify-content:space-between;
  padding-inline:var(--pad);
  visibility:hidden;
}
.matline::before{
  content:"";
  position:absolute;left:0;right:0;top:50%;
  height:2px;margin-top:-1px;
  background:var(--blue);
  opacity:.75;
  box-shadow:0 0 26px 3px rgba(30,134,226,1),
             0 0 70px 12px rgba(30,134,226,.53);
}
.matline__label,.matline__name{
  position:relative;
  font-size:clamp(.72rem,.9vw,.86rem);
  letter-spacing:.14em;
  text-transform:uppercase;
  color:#fff;
  background:var(--blue);
  border-radius:99px;
  padding:6px 16px;
}

/* ==========================================================================
   how it works — three numbered cards, sharing the use-case card treatment
   ========================================================================== */
.steps{
  width:min(1080px,92vw);
  display:grid;
  grid-template-columns:repeat(3,minmax(0,1fr));
  gap:clamp(16px,2.2vw,30px);
  list-style:none;padding:0;margin:0;
  text-align:left;
}
.step{
  background:#fff;
  border-radius:26px;
  padding:clamp(24px,2.6vw,40px);
  display:grid;gap:10px;align-content:start;
  box-shadow:0 2px 18px rgba(0,0,0,.06);
}
.step__num{
  font-family:var(--display);
  font-weight:300;
  font-size:clamp(2rem,3.4vw,3rem);
  line-height:1;
  letter-spacing:-.02em;
  color:var(--ink);
  margin-bottom:clamp(6px,1vh,14px);
}
.step__name{
  font-family:var(--display);
  font-weight:400;
  font-size:clamp(1.2rem,1.7vw,1.5rem);
  line-height:1.15;
  letter-spacing:-.01em;
}
.step__copy{
  font-size:clamp(.94rem,1.1vw,1.05rem);
  line-height:1.5;
  color:var(--ink-60);
}

/* ==========================================================================
   use cases — four white cards, each captioned above
   ========================================================================== */
.cases{
  /* wider than the reading column: four cards need the room */
  width:min(1080px,92vw);
  display:grid;
  grid-template-columns:repeat(4,minmax(0,1fr));
  gap:clamp(16px,2.2vw,30px);
  list-style:none;padding:0;margin:0;
}
.case{display:grid;justify-items:center;align-content:start}
.case__label{
  font-size:clamp(.85rem,1vw,.98rem);
  line-height:1.2;
  color:var(--ink-60);
  text-align:center;
  margin:0;
}
.case__box{
  /* the caption sits inside the card with the artwork, so the white runs
     behind both. The artwork carries its own transparent margin — an uneven
     one, 24px on the slide mocks against 64px on the square profile icon — so
     the card adds only a little of its own on top */
  width:100%;
  background:#fff;
  border-radius:26px;
  padding:clamp(12px,1.2vw,18px) clamp(8px,0.9vw,14px) clamp(8px,0.9vw,14px);
  display:grid;justify-items:center;gap:10px;
  /* the page sits on a pale tint, so the card needs a little lift to read
     as white rather than as a slightly lighter patch of background */
  box-shadow:0 2px 18px rgba(0,0,0,.06);
}
.case__box img{width:100%;height:auto;display:block}

/* ==========================================================================
   cta + footer
   ========================================================================== */
.sec--cta{
  display:grid;place-items:center;
  gap:clamp(36px,6vh,72px);
  padding-block:clamp(70px,12vh,150px);
}
.foot{
  position:relative;
  display:grid;place-items:center;
  gap:16px;
  padding:clamp(40px,7vh,90px) var(--pad) clamp(56px,9vh,110px);
  text-align:center;
}
.foot__socials{display:flex;gap:clamp(18px,2.4vw,28px);list-style:none;padding:0;margin:0}
.foot__social{
  color:var(--ink);
  display:grid;place-items:center;
  transition:transform .4s var(--ease-io),opacity .3s var(--ease);
}
.foot__social:hover,.foot__social:focus-visible{transform:translateY(-2px);opacity:.55}
.foot__social svg{width:24px;height:24px;display:block}
.foot__copy{font-size:.95rem;color:var(--ink)}

/* ==========================================================================
   responsive
   ========================================================================== */
/* every gap in the header the same 100px — item to item and item to mark. The
   labels are uppercase, which is wider than it looks, so the flat spacing
   waits for 1320px rather than pushing the row off both edges.

   The two side groups also take an equal share of the width, which is what
   puts the mark on the centre line. Left-aligned in a centred row it never
   could: the right group carries the Generator button and the switcher and
   runs 150-240px wider than the left in every language, and a centred row
   splits that difference, so the mark sat up to 119px left of centre. Equal
   boxes with the left group pushed to its right edge and the right group to
   its left keeps every gap at 100px and puts the mark exactly halfway. */
@media (min-width:1320px){
  .hdr{gap:100px}
  .hdr__side{flex:1;min-width:0;gap:100px}
  .hdr__side--l{justify-content:flex-end}
  /* the right group is the wider one, so it is what decides whether half the
     width is enough. Between 1320 and 1440 it needs to pull its items a
     little closer than 100px to fit; past that there is room for the full
     spacing on both sides. */
  .hdr__side--r{justify-content:flex-start;gap:84px}
}
@media (min-width:1440px){
  .hdr__side--r{gap:100px}
}
/* Japanese writes its nav out in full — よくある質問 and ジェネレーター are 92px
   and 149px against 30px for FAQ — so its right-hand group is ~300px of text
   where every other language is ~260px, and at the shared spacing it runs past
   the edge of its half. It gets its own gap until the window is wide enough to
   carry the full 100px. Specificity puts these ahead of the rules above
   whatever the order; source order is what settles the two against each
   other. */
@media (min-width:1320px){
  html[lang="ja"] .hdr__side--r{gap:68px}
}
@media (min-width:1500px){
  html[lang="ja"] .hdr__side--r{gap:100px}
}

@media (max-width:900px){
  :root{--hdr-h:76px}
  .pill{height:40px;padding-inline:16px;font-size:.88rem}
  .navlink{height:40px;font-size:.84rem}
  .navcta{height:34px;padding-inline:15px}
  .lang__now{height:40px;font-size:.84rem}
  .cases{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media (max-width:620px){
  :root{--pad:8px}
  .cases{grid-template-columns:repeat(2,minmax(0,1fr));width:100%;gap:12px}
  .steps{grid-template-columns:minmax(0,1fr);width:100%}
  .sec--steps .wrap{padding-inline:10%}
  #faq .wrap{padding-inline:20%}
  /* hamburger left, mark centred, language switcher right. The mark lands on
     the centre line because the two outer slots each take half of what is
     left, the same trick the desktop header uses. The 20% inset is symmetric,
     so it moves both ends inward without pulling the mark off centre — and
     both panels hang off their own trigger, so they follow it in. */
  .hdr{gap:0;justify-content:space-between;padding-inline:20%}
  .menu{display:block;flex:1}
  .hdr__side--l{display:none}
  /* The right group IS the right-hand slot here, rather than being flattened
     into the header with display:contents so the switcher could take the slot
     itself. WebKit is unreliable about promoting the children of a
     display:contents box to flex items, and when it does not, the switcher
     stops being a flex item, .menu absorbs all the free space on its own, and
     the switcher ends up jammed against the mark — which is exactly what iOS
     Safari showed while Chrome was fine. Pushing its own content to the right
     needs no such promotion. */
  .hdr__side--r{flex:1;justify-content:flex-end;gap:0}
  .hdr__side--r .navlink{display:none}
  /* Nine items have to share the width, and the labels are far wider in some
     languages than in English — VOORBEELDEN and TOEPASSING against Examples
     and Cases, and all of it uppercase, which costs about a tenth again.
     Below 620px the type tracks the viewport so the row still lands inside
     both edges on a 360px phone instead of running off the right. */
  .navlink{height:34px;font-size:clamp(.56rem,2.92vw,.84rem);letter-spacing:-.02em}
  .navcta{height:29px;padding-inline:clamp(5px,2.1vw,9px)}
  .navcta::before{inset:-3px;filter:blur(5px)}
  .lang__now{height:34px;font-size:clamp(.56rem,2.92vw,.84rem);letter-spacing:0}
  /* the switcher is the last item in a full-width header, so the panel hangs
     from its right edge — centring it on the chip put a third of the menu off
     the side of the screen */
  .lang__menu{right:0;min-width:118px;padding:6px}
  .row{grid-template-columns:1fr;gap:14px}
  .rows{width:100%;text-align:center}
  /* centred text cannot hang a dash off to the left, so it goes inline */
  .row__list li{padding-left:0}
  .row__list li::before{position:static;margin-right:.45em}
  .marquee__row{gap:36px}
  .marquee__row--media{gap:14px}
  .foot{padding-bottom:clamp(40px,7vh,70px)}
}

/* ==========================================================================
   reduced motion / no-js
   ========================================================================== */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.001ms!important;animation-iteration-count:1!important;
    transition-duration:.001ms!important;
  }
}
html.no-js .preloader{display:none}
