/* ritsutakigawa.com — ATELIER INK (design locked 2026-07-24)
   Concept B winner + the gold from the archived GLOBAL VOICE Atelier concept.
   Tokens: cream paper, warm ink, sophisticated gold. Serif display
   (Instrument Serif EN / Shippori Mincho JP), Manrope + Noto Sans JP body.
   Photo renders in COLOR (user call — no grayscale/desaturation filters).
   No inline styles anywhere (CSP: no 'unsafe-inline'). */

:root {
  --paper: #fbf7ef;
  --stone: #f1ebdd;
  --ink: #1a1714;
  --ink-2: rgba(26, 23, 20, 0.62);
  --line: rgba(26, 23, 20, 0.16);
  --gold: #b08a3e;
  --gold-soft: #c9a968;
  /* text-grade golds (same family, darkened to clear WCAG-AA on cream):
     --gold-text for LARGE display type (≥3:1), --gold-dark for small text (≥4.5:1) */
  --gold-text: #9d7a33;
  --gold-dark: #8a6b2d;
  --maxw: 1060px;
  --narrow: 760px;
  --gutter: 22px; /* .narrow's horizontal padding — shared with the hero
                     photo's absolute left, which anchors to the padding box
                     and would otherwise sit outside the gutter */
  --serif: "Instrument Serif", "Shippori Mincho", serif;
  --jserif: "Shippori Mincho", "Instrument Serif", serif;
  --body: "Manrope", "Noto Sans JP", sans-serif;
}

* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  font-family: var(--body);
  color: var(--ink);
  background: var(--paper);
  line-height: 1.9;
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; display: block; }
a { color: inherit; }
::selection { background: var(--ink); color: var(--paper); }
/* longhand on purpose: sections set their vertical rhythm via `main section`
   (lower specificity) — a padding SHORTHAND here would zero it out */
.narrow { max-width: var(--narrow); margin: 0 auto; padding-left: var(--gutter); padding-right: var(--gutter); }

/* ---- nav ---- */
.nav {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 16px;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 26px 22px;
}
.nav__brand {
  font-family: var(--serif);
  font-style: italic;
  font-size: 19px;
  letter-spacing: 0.06em;
  text-decoration: none;
  color: var(--gold-dark);
}
.nav__links { display: flex; align-items: center; gap: 26px; }
.nav__links a {
  text-decoration: none;
  font-size: 12px;
  letter-spacing: 0.2em;
  color: var(--ink);
  opacity: 0.5;
  transition: opacity 0.25s;
}
.nav__links a:hover { opacity: 1; }
.nav__pill {
  font-family: var(--body);
  font-size: 11px;
  letter-spacing: 0.1em;
  border: 1px solid var(--ink);
  border-radius: 999px;
  background: none;
  color: var(--ink);
  padding: 5px 15px;
  cursor: pointer;
  transition: all 0.3s;
}
.nav__pill:hover { background: var(--ink); color: var(--paper); }
.nav__burger { display: none; }

@media (max-width: 700px) {
  .nav__burger {
    display: grid; gap: 4px; background: none; border: 0; cursor: pointer; padding: 8px;
    justify-self: end;
  }
  .nav__burger span { width: 20px; height: 1.5px; background: var(--ink); }
  .nav__links {
    display: none;
    grid-column: 1 / -1;
    flex-direction: column; align-items: flex-start; gap: 14px;
    padding: 14px 4px 4px;
    border-top: 1px solid var(--line);
  }
  .nav__links.open { display: flex; }
}

/* ---- hub hero ---- */
.hero { padding: 72px 0 48px; }
/* photo spans the text block EXACTLY (2026-07-27, user call): top at the
   headline cap, bottom at the sub baseline, at every row-layout width. Flex
   stretch alone couldn't do it — the img's intrinsic ratio floors its height
   8-17px past the text at the 2-line breakpoints — so the photo sits out of
   flow and the text column alone defines the hero height. object-position
   biases the crop upward so shorter text blocks trim the sweater, not the
   face. Column layout (≤640px) returns it to flow as a fixed box. */
.hero__inner { position: relative; display: flex; align-items: stretch; gap: 44px; }
.hero__photo {
  position: absolute;
  /* left anchors to the PADDING box of .hero__inner — left:0 would ignore
     the .narrow gutter and shift the photo 22px left of every other section
     (user caught it live, 7/27) */
  top: 0; left: var(--gutter);
  width: 190px;
  height: 100%; /* NOT top+bottom: an img is a replaced element, so height:auto
                   resolves to the intrinsic ratio and bottom gets ignored */
  object-fit: cover;
  /* 30% x: the head sits left of the square source's center — probe-picked
     from rendered candidates (0/15/30/50) to center the face in the crop */
  object-position: 30% 25%;
  flex: 0 0 auto;
}
.hero__text { margin-left: 234px; } /* photo 190 + the 44px gutter */
.hero__tagline {
  font-family: var(--jserif);
  font-weight: 400;
  font-size: clamp(27px, 4.4vw, 42px);
  line-height: 1.55;
  margin-bottom: 20px;
  /* keep-all stops mid-word CJK breaks (ナレー/ター class); ZWSP hints in the
     source give it legal break points; overflow-wrap is the iOS-proof net
     (Kelly-rail lesson 7/22) */
  word-break: keep-all;
  overflow-wrap: anywhere;
  color: var(--gold-text);
}
/* EN runs ~2.2× the character count of the JP tagline; at the shared size it
   wraps to one more line than the JP, so the language toggle used to reflow
   everything below the hero. The EN layer takes a smaller clamp tuned so BOTH
   languages render the same line count (probe-verified at 1440/1024/768px —
   re-measure if the tagline copy ever changes). script.js flips the html lang
   attribute on toggle (a11y-correct anyway), which is what this hooks. */
html[lang="en"] .hero__tagline {
  font-size: clamp(24px, 3.6vw, 34px);
  /* 1.9 is not taste, it's arithmetic: 3.6vw × 1.9 ≈ 4.4vw × 1.55, so the
     JP and EN line BOXES are the same height at every width — equal line
     counts then mean equal block height, and the toggle moves nothing below */
  line-height: 1.9;
}
.hero__sub { color: var(--ink-2); font-size: 15px; max-width: 30em; }
@media (max-width: 640px) {
  .hero { padding: 48px 0 36px; }
  .hero__inner { flex-direction: column-reverse; align-items: flex-start; }
  .hero__photo { position: static; width: 150px; height: 180px; } /* back in flow: fixed box */
  .hero__text { margin-left: 0; }
}

/* ---- doors ---- */
.doors {
  display: grid; grid-template-columns: 1fr 1fr; gap: 24px;
  padding-top: 28px; padding-bottom: 16px;
}
.door {
  border: 1px solid rgba(26, 23, 20, 0.25);
  padding: 38px 32px;
  text-decoration: none;
  transition: all 0.3s;
}
.door:hover { border-color: var(--ink); background: var(--stone); }
.door__title {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: 26px;
  letter-spacing: 0.02em;
  margin-bottom: 8px;
  color: var(--gold-text);
}
.door__desc { color: var(--ink-2); font-size: 13px; }
@media (max-width: 560px) { .doors { grid-template-columns: 1fr; } }

/* ---- shared section chrome ---- */
.section__label {
  display: flex;
  align-items: center;
  gap: 18px;
  font-size: 11px;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--ink);
  opacity: 0.45;
  font-weight: 500;
  margin: 0 0 26px;
}
.section__label::after { content: ""; height: 1px; flex: 1; background: var(--ink); opacity: 0.35; }
main section { padding: 44px 0; }

/* ---- voice / work heroes ---- */
.vhero, .whero { background: var(--stone); padding: 64px 0; }
.vhero__line, .whero__line {
  font-family: var(--jserif);
  font-weight: 400;
  font-size: clamp(19px, 2.7vw, 26px);
  line-height: 2;
}

/* ---- demos + player ---- */
.demo { margin-bottom: 30px; }
.demo__title { font-size: 13px; letter-spacing: 0.04em; margin-bottom: 10px; }
.demos__dry { font-size: 13px; color: var(--ink-2); margin-top: 22px; }
.player {
  display: flex; align-items: center; gap: 14px;
  position: relative;
  contain: inline-size;
  padding: 2px 0;
}
.player__btn {
  background: none; border: 0; cursor: pointer; color: var(--ink);
  display: grid; place-items: center; flex: 0 0 auto;
  transition: all 0.3s;
}
.player__play {
  width: 42px; height: 42px;
  border: 1px solid var(--ink);
  border-radius: 999px;
}
.player__play:hover { background: var(--ink); color: var(--paper); }
.player__vol, .player__more { width: 30px; height: 30px; opacity: 0.55; }
.player__vol:hover, .player__more:hover { opacity: 1; }
.player__btn svg { width: 17px; height: 17px; }
.player__time { font-size: 12px; color: var(--ink-2); white-space: nowrap; flex: 0 0 auto; }
.player__track { flex: 1; height: 2px; background: rgba(26, 23, 20, 0.18); cursor: pointer; min-width: 40px; }
.player__fill { height: 100%; width: 0; background: var(--gold); }
.player__menu {
  position: absolute; right: 4px; top: calc(100% + 6px); z-index: 5;
  background: var(--paper); border: 1px solid var(--line);
  box-shadow: 0 8px 24px rgba(26, 23, 20, 0.1);
}
.player__menu-item { display: block; padding: 10px 20px; font-size: 13px; text-decoration: none; white-space: nowrap; }
.player__menu-item:hover { background: var(--stone); }

/* ---- credits / studio / capability / creds lists ---- */
.credits__list, .studio__list, .capability__list, .creds__list {
  list-style: none; display: grid; gap: 16px;
}
.credits__list li, .studio__list li, .capability__list li, .creds__list li {
  font-size: 14px;
  padding-left: 26px;
  position: relative;
}
.credits__list li::before, .studio__list li::before,
.capability__list li::before, .creds__list li::before {
  content: "—";
  position: absolute; left: 0;
  color: var(--gold);
}
.credits__list a, .capability__list a { color: var(--gold); text-underline-offset: 3px; }
.credits__list a:hover, .capability__list a:hover { color: var(--ink); }

/* ---- GLOBAL VOICE block ---- */
.gv__text { font-size: 14px; margin-bottom: 10px; }
.gv__links { font-size: 14px; }
.gv__links a { color: var(--gold); text-underline-offset: 3px; }
.gv__links a:hover { color: var(--ink); }

/* ---- offer / cases / feature ---- */
.offer__header {
  font-family: var(--jserif);
  font-weight: 500;
  font-size: 21px;
  line-height: 1.8;
  margin-bottom: 14px;
}
.offer__body, .feature__body { font-size: 14px; color: var(--ink-2); }
.case { margin-bottom: 34px; padding-left: 26px; border-left: 1px solid var(--gold-soft); }
.case__title { font-size: 16px; font-weight: 600; margin-bottom: 8px; }
.case__body { font-size: 14px; color: var(--ink-2); }
.case__link { font-size: 14px; margin-top: 8px; }
.case__link a { color: var(--gold); text-underline-offset: 3px; }
.case__link a:hover { color: var(--ink); }
.feature__body a { color: var(--gold); text-underline-offset: 3px; }
.feature__body a:hover { color: var(--ink); }

/* ---- contact / form ---- */
.contact { background: var(--stone); }
.contact__lead, .contact__ease { font-size: 14px; margin-bottom: 8px; }
.contact__ease { color: var(--ink-2); }
.form { display: grid; gap: 22px; margin-top: 26px; max-width: 560px; }
.form__botcheck { position: absolute; left: -9999px; }
.form__row { display: grid; gap: 4px; font-size: 12px; letter-spacing: 0.08em; }
.form__row span { opacity: 0.55; }
.form__row input, .form__row textarea {
  font-family: var(--body);
  font-size: 14px;
  border: 0;
  border-bottom: 1px solid rgba(26, 23, 20, 0.35);
  padding: 8px 2px;
  background: transparent;
  color: var(--ink);
  border-radius: 0;
}
.form__row input:focus, .form__row textarea:focus {
  outline: none;
  border-bottom-color: var(--gold);
}
/* placeholders read as pre-filled values at the UA default darkness (user
   flag 2026-07-27) — pull them well under the label opacity; explicit
   opacity:1 stops Firefox double-dimming its own placeholder opacity */
.form__row input::placeholder, .form__row textarea::placeholder {
  color: rgba(26, 23, 20, 0.3);
  opacity: 1;
}
.form__status { font-size: 13px; color: var(--gold); }
.form__submit {
  font-family: var(--body);
  font-size: 13px;
  letter-spacing: 0.15em;
  background: none;
  color: var(--ink);
  border: 1px solid var(--ink);
  border-radius: 999px;
  padding: 12px 40px;
  cursor: pointer;
  justify-self: start;
  transition: all 0.3s;
}
.form__submit:hover { background: var(--ink); color: var(--paper); }
.form__submit:disabled { opacity: 0.4; cursor: default; }

/* ---- footer ---- */
.footer {
  display: flex; justify-content: space-between; align-items: center;
  max-width: var(--maxw); margin: 0 auto; padding: 30px 22px;
  border-top: 1px solid var(--line);
  font-size: 12px; color: var(--ink-2);
}

/* ---- motion (added 2026-07-24) ----
   Restrained on purpose (ATELIER INK): a short fade + a small rise. No scale,
   no bounce, no parallax, no scroll-pinning — the page never holds the reader
   still. Two mechanisms, deliberately separate:

   1. HERO ENTRANCE — pure CSS, runs on load. The hidden state lives ONLY
      inside the keyframes, so if the animation never runs (unsupported,
      disabled) the element is simply visible. No JS involved, so it cannot
      flash: the from-state is in effect from first paint.
   2. REVEAL-ON-SCROLL — script.js adds `.reveal`; CSS never hides anything on
      its own. See the safety rules in script.js.

   Both layers are neutralised under prefers-reduced-motion below. */
/* Entrance timing (slowed 2026-07-24, user call — the first pass read as too
   quick). 1.7s per element with the stagger spread to 0.15 / 0.45 / 0.8 / 1.2s,
   so the hero settles at ~2.9s. The travel went 12px -> 18px with it: a small
   move stretched over a long duration reads as lag, not as intent — distance
   and duration have to move together. This is the upper end of tasteful; past
   ~3s a returning visitor starts waiting on the page. */
@keyframes ink-rise {
  from { opacity: 0; transform: translateY(18px); }
}
.hero__photo, .hero__tagline, .hero__sub,
.vhero__line, .whero__line {
  animation: ink-rise 1.7s cubic-bezier(0.22, 0.61, 0.36, 1) both;
}
/* re-spread 2026-07-27 after the kicker was removed (name deduplication):
   three elements now carry the same ~2.9s settle the four-element stagger had */
.hero__photo   { animation-delay: 0.15s; }
.hero__tagline { animation-delay: 0.6s; }
.hero__sub     { animation-delay: 1.2s; }

/* The /voice + /work heroes are a SINGLE line — no stagger to spread the
   sequence over, so at the hub's timing they finished in roughly half the wall
   clock and read as abrupt beside it. Slowed twice on user call (2026-07-24);
   settle is now ~4.5s.

   THE EASING IS DOING MORE WORK HERE THAN THE DURATION. The shared curve
   (0.22, 0.61, 0.36, 1) is a hard ease-out: it dumps most of the opacity change
   into the first third and spends the rest of the time on an almost-invisible
   tail, so raising the duration alone barely moved what the eye actually
   perceives — that is why 2.4s still read as fast. This curve is near
   symmetric, so the fade is distributed across the whole 4s and the perceived
   length tracks the number. Change the curve, not just the duration, if this
   ever needs tuning again. */
.vhero__line, .whero__line {
  animation-duration: 4s;
  animation-delay: 0.5s;
  animation-timing-function: cubic-bezier(0.35, 0, 0.45, 1);
}

/* Slowed 2026-07-24 (user: 0.8s was barely perceptible mid-scroll) — same
   curve lesson as the single-line heroes above: near-symmetric easing so the
   fade spreads across the full duration instead of vanishing into the first
   quarter-second, and the travel grew with the duration (14px → 24px).
   1.8s → 1.7s on 7/25 (Kelly-rail round 4 port): one duration across both
   sites, keyed to the hub hero elements' 1.7s. */
.reveal { opacity: 0; transform: translateY(24px); }
.reveal--in {
  opacity: 1;
  transform: none;
  transition: opacity 1.7s cubic-bezier(0.35, 0, 0.45, 1),
              transform 1.7s cubic-bezier(0.35, 0, 0.45, 1);
}

/* Standalone hairlines never translate (2026-07-25, ported from the Kelly
   site the same day): a 1px line re-rasterized at fractional offsets during
   its section's 24px travel snaps across pixel rows on 1× desktop displays —
   visible flicker (invisible at mobile DPR). A child cannot opt out of its
   parent's transform, so the section-label rules and the contact form's input
   underlines SIT OUT the travel: hidden while the section rises, then a
   purely SEQUENTIAL 1.25s fade from 1.7s — the moment the travel ends
   (round 4, 7/25: zero overlap = zero flicker risk; ruled totals land at
   2.95s, matching the Kelly-rail hero settle).
   Scoped under the JS-added .reveal/.reveal--in only — no-JS, reduced motion,
   and old engines never match, so nothing is hidden without the reveal
   running. The label rule fades back to its design 0.35, not 1. The inputs
   use an ANIMATION, not a transition — a transition on border-bottom-color
   would outlive the entrance and turn the instant gold :focus response into a
   4.4s crawl; the animation releases the property when it ends (and while it
   runs, `backwards` covers the 1.8s delay). The :not(.reveal--in) scope on
   the hidden state matters: .reveal is never removed, so a bare .reveal rule
   would re-hide the underline the moment the animation released it. */
.reveal .section__label::after { opacity: 0; }
.reveal--in .section__label::after {
  opacity: 0.35;
  transition: opacity 1.25s cubic-bezier(0.35, 0, 0.45, 1) 1.7s;
}
@keyframes underline-fade {
  from { border-bottom-color: transparent; }
}
.reveal:not(.reveal--in) .form__row input,
.reveal:not(.reveal--in) .form__row textarea { border-bottom-color: transparent; }
.reveal--in .form__row input, .reveal--in .form__row textarea {
  animation: underline-fade 1.25s cubic-bezier(0.35, 0, 0.45, 1) 1.7s backwards;
}

/* Language-toggle fade (2026-07-27, user calls same day — final shape) —
   the pill swap re-runs the entrance ONLY where an entrance exists: the hero
   elements each page animates on first paint (script.js whitelist =
   .hero__tagline / .hero__sub / .vhero__line / .whero__line, the same list
   the reduced-motion block names). Identical motion to that entrance: 1.7s,
   same curve, 24px rise. Everything else swaps instantly (fading every
   changed element read as noise — user call), which also keeps hairlines
   and inline elements out of the animation entirely. */
@keyframes lang-fade { from { opacity: 0; transform: translateY(24px); } }
.langfade { animation: lang-fade 1.7s cubic-bezier(0.35, 0, 0.45, 1); }

/* Surgical on purpose — no blanket `* { animation: none !important }` reset:
   that would also kill the hover/focus colour transitions, which aren't motion
   and are load-bearing for affordance. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .hero__photo, .hero__tagline, .hero__sub,
  .vhero__line, .whero__line { animation: none; }
  /* script.js never arms .langfade under reduced motion; CSS agrees on its own */
  .langfade { animation: none; }
  .reveal, .reveal--in { opacity: 1; transform: none; transition: none; }
  /* the hairline sit-out too — script.js never arms under reduced motion, so
     these normally can't match, but the CSS layer neutralises on its own */
  .reveal .section__label::after, .reveal--in .section__label::after { opacity: 0.35; transition: none; }
  .reveal:not(.reveal--in) .form__row input, .reveal:not(.reveal--in) .form__row textarea,
  .reveal--in .form__row input, .reveal--in .form__row textarea {
    border-bottom-color: rgba(26, 23, 20, 0.35); /* the .form__row base value */
    animation: none;
  }
}

/* ---- honest 404 ---- */
.err__main { min-height: 70vh; display: grid; place-content: center; text-align: center; gap: 16px; padding: 40px 22px; }
.err__code { font-family: var(--serif); font-weight: 400; font-size: 72px; color: var(--gold); }
.err__msg { color: var(--ink-2); }
.err__home { color: var(--ink); text-underline-offset: 3px; }
