// site.jsx — YuHouse Academy TOP page // Luxury hair-academy site. Photo placeholders use subtly-striped SVG with // monospace labels per the design system; the user will swap in real imagery. const { useState, useEffect, useRef } = React; // ── Brand tokens ──────────────────────────────────────────────────────────── // Palette pivot: white-first, with pink + gold as accent pair. // Pink = warm primary accent, Gold = secondary / metallic accent. const BRAND = { black: '#1A1A1A', // reserved for text only — no full-bleed black surfaces ink: '#1A1A1A', mute: '#8A847C', white: '#FFFFFF', cream: '#FBF7F0', // soft warm white — primary surface beige: '#F5EFE6', // section divider tone beigeDeep: '#ECE3D2', pink: '#EF859A', // primary accent pinkSoft: '#F8DDE2', gold: '#E5B34F', // secondary accent goldSoft: '#F1D89A', hair: 'rgba(26,26,26,.08)', }; // Back-compat aliases: existing call sites used BRAND.goldLight; the new // palette names this goldSoft. Keep both so unrelated files keep working // while the redesign rolls through. BRAND.goldLight = BRAND.goldSoft; // ── Placeholder photo ────────────────────────────────────────────────────── // Striped tonal block + monospace caption describing intended subject. // Tone is "warm" (beige) or "dark" (black). Aspect = w/h in CSS aspect-ratio. function Photo({ label, tone = 'warm', ratio = '4 / 5', radius = 0, style = {} }) { // Tones map to the new white-based palette: // 'warm' → cream / beige stripes (default light surface) // 'blush' → soft pink stripes (hero / feature accents) // 'dark' → kept for legacy callers; renders as a softer charcoal const stripes = { warm: ['#F0E8D7', '#E8DEC6'], blush: ['#FBE3E6', '#F4D2D8'], dark: ['#26221E', '#2E2925'], }[tone] || ['#F0E8D7', '#E8DEC6']; const isDark = tone === 'dark'; const cap = isDark ? 'rgba(255,255,255,.55)' : 'rgba(26,26,26,.42)'; const tag = isDark ? 'rgba(229,179,79,.75)' : 'rgba(239,133,154,.85)'; return (
{'// PHOTO'}
{label}
); } // ── Eyebrow ──────────────────────────────────────────────────────────────── // English label above a Japanese heading. Standard rhythm device for this site. function Eyebrow({ children, color = BRAND.gold }) { return (
{children}
); } // ── Section title (EN big serif + JP smaller mincho) ─────────────────────── function SectionTitle({ en, jp, light = false, align = 'left' }) { return (

{en}

{jp && (
{jp}
)}
); } // ── Button ───────────────────────────────────────────────────────────────── // Primary = ink fill, white text, pink fill on hover (pink is the lead accent). // Secondary = transparent w/ ink border on light surfaces, white on dark. function Btn({ children, variant = 'primary', onLight = true, arrow = true, href = '#' }) { const [hov, setHov] = useState(false); const isPrimary = variant === 'primary'; const base = { display: 'inline-flex', alignItems: 'center', gap: 14, padding: '18px 28px', minWidth: 220, fontFamily: '"Noto Sans JP", sans-serif', fontSize: 13, fontWeight: 500, letterSpacing: '.16em', textDecoration: 'none', cursor: 'pointer', border: '1px solid', borderRadius: 0, transition: 'background .35s ease, color .35s ease, border-color .35s ease', justifyContent: 'space-between', }; let styled; if (isPrimary) { styled = hov ? { ...base, background: BRAND.pink, color: BRAND.white, borderColor: BRAND.pink } : { ...base, background: BRAND.ink, color: BRAND.white, borderColor: BRAND.ink }; } else { // onLight=true means we're sitting on a white/cream surface styled = hov ? { ...base, background: onLight ? BRAND.ink : BRAND.white, color: onLight ? BRAND.white : BRAND.ink, borderColor: onLight ? BRAND.ink : BRAND.white } : { ...base, background: 'transparent', color: onLight ? BRAND.ink : BRAND.white, borderColor: onLight ? BRAND.ink : BRAND.white }; } return ( setHov(true)} onMouseLeave={() => setHov(false)}> {children} {arrow && ( )} ); } // ── Top navigation ───────────────────────────────────────────────────────── // Always-light variant: cream-tinted blur, dark text. The hairline border // fades in on scroll so the nav has presence over content. function Nav() { const [scrolled, setScrolled] = useState(false); useEffect(() => { const on = () => setScrolled(window.scrollY > 40); on(); window.addEventListener('scroll', on, { passive: true }); return () => window.removeEventListener('scroll', on); }, []); const items = [ ['CONCEPT', '#concept'], ['MESSAGE', '#message'], ['LECTURERS', '#lecturers'], ['COURSES', '#courses'], ['FAQ', '#faq'], ['ACCESS', '#access'], ]; return ( ); } // ── Hero ─────────────────────────────────────────────────────────────────── // Editorial split: oversized serif headline left, hero photo right. // Cream surface, pink + gold accents. A single half-bleed photo (using one of // the lecturer shots until a proper hero is supplied) anchors the right side. function Hero() { return (
{/* Faint outsized word watermark */} {/* Hairline frame */}
{/* Vertical EN tagline at left edge */}
Hair Artist Academy  ·  Est. Tokyo
{/* Frame number top-right */}
N° 01 / HERO
{/* Left: text */}
YuHouse Academy · 2026

Technique
expands{' '}
expression.

技術で、表現の幅を広げる。
美容師のための、実践型ヘアアカデミー。

講習を見る お問い合わせ
{/* Right: hero photo card */}
{/* Soft pink wash for tonal unity */}
{/* Pink badge top-right */}
SINCE 2026
{/* Gold tick top-left */}
FIG. A — ACADEMY
{/* Caption bar bottom */}
Hair, as expression. 01 / 09
{/* Scroll cue */}
SCROLL
); } // ── Concept / Intro ──────────────────────────────────────────────────────── function Concept() { return (
About — 01

美容師・ヘアアーティストが、現場で活かせる
技術を実践的に学ぶための専門アカデミー。

シールエクステ、羽エクステ、ブラックヘアー、カラー、カットなど、多様な技術講習を通じて、表現の幅とサロンワークの可能性を広げます。第一線で活躍する講師陣が、サロンワークの延長としての教育を提供します。

{[ ['10+', 'Lecturers', '在籍講師'], ['7', 'Categories', '講習カテゴリ'], ['1on1', 'Approach', '実践指導'], ].map(([n, en, jp]) => (
{n}
{en}
{jp}
))}
{/* Right photo stack */}
FIG. 01
); } window.Photo = Photo; window.Eyebrow = Eyebrow; window.SectionTitle = SectionTitle; window.Btn = Btn; window.Nav = Nav; window.Hero = Hero; window.Concept = Concept; window.BRAND = BRAND;