// Variant D · v5 — White × Blue ブランドミニマル / 抽象Canvas+SVG / キネティックタイポ
// 写真ゼロ。線・円・グリッド・ノイズだけで世界観を構築。
const hbcp = {
white:'#FFFFFF',
paper:'#FAFAFA',
paperWarm:'#F5F4F0',
ink:'#0E0E14',
inkSoft:'#3A3A45',
inkLight:'#8A8A93',
line:'#E8E6DF',
lineSoft:'#F0EEE8',
blue:'#1F61AB',
blueDeep:'#0F3B72',
blueLight:'#E8EFF8',
blueGhost:'#F4F8FD',
};
const fontEN = '"Cormorant Garamond", "Times New Roman", serif';
const fontENSans = '"Inter", system-ui, sans-serif';
const fontJP = '"Zen Kaku Gothic New", "Noto Sans JP", sans-serif';
const fontJPSerif= '"Shippori Mincho", "Noto Serif JP", serif';
const fontMono = '"JetBrains Mono", monospace';
const ease = 'cubic-bezier(.16,.88,.2,1)';
const styles = `
@import url('https://fonts.googleapis.com/css2?family=Shippori+Mincho:wght@400;500;600;700;800&family=Cormorant+Garamond:ital,wght@0,300;0,400;0,500;1,300;1,400&family=Zen+Kaku+Gothic+New:wght@300;400;500;700;900&family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
/* スプラッシュは front-page.php 側で定義(document.body 直下にマウント)。
variant-d.jsx 内の旧 HBSplash 用 CSS は撤去済み。 */
@keyframes hb-fade { to { opacity:1; } }
/* ====== 共通 reveal ====== */
.hb-chars { display:inline; }
.hb-chars .hb-line { display:block; overflow:hidden; padding-bottom:.22em; }
.hb-chars .hb-c {
display:inline-block; opacity:0; transform: translateY(105%);
transition: opacity .55s ${ease}, transform .55s ${ease};
}
.hb-chars.is-in .hb-c { opacity:1; transform:translateY(0); }
/* ヒーロー内のテキストはリビール待ちにせず常時表示(IO/transitionのバグで非表示になる事故回避) */
.hb-hero .hb-chars .hb-c,
.hb-hero .hb-up { opacity:1 !important; transform:none !important; transition:none !important; }
.hb-up { opacity:0; transform: translateY(28px); transition: opacity .6s ${ease}, transform .6s ${ease}; }
.hb-up.is-in { opacity:1; transform: translateY(0); }
/* アクセシビリティ: 動きを抑制したいユーザーには即時静止表示 */
@media (prefers-reduced-motion: reduce) {
.hb-chars .hb-c, .hb-up { opacity:1 !important; transform:none !important; transition:none !important; }
}
/* ====== Hero ====== */
.hb-hero { position:relative; padding:72px 32px 64px; overflow:hidden; background:${hbcp.white}; }
.hb-hero-canvas { position:absolute; inset:0; width:100%; height:100%; }
.hb-hero-svg { position:absolute; inset:0; width:100%; height:100%; pointer-events:none; }
.hb-hero-display {
font-family:${fontJP}; font-weight:900; letter-spacing:-.02em; line-height:1.18;
font-size:72px; color:${hbcp.ink}; margin:0;
}
.hb-hero-display em {
font-family:${fontEN}; font-style:italic; font-weight:300; font-size:.7em;
letter-spacing:.005em; color:${hbcp.blue}; line-height:1.1;
}
.hb-hero-display .hb-accent { border-bottom: 3px solid ${hbcp.blue}; padding-bottom:.05em; }
/* 縦罫 */
.hb-vrule {
position:absolute; top:0; bottom:0; width:1px; background:${hbcp.line}; z-index:0;
}
/* ====== Section common ====== */
.hb-section-head { display:flex; align-items:baseline; gap:18px; padding-bottom:18px; border-bottom:1px solid ${hbcp.line}; margin-bottom:40px; }
.hb-section-head-en {
font-family:${fontENSans}; font-size:11px; font-weight:500; letter-spacing:.3em; color:${hbcp.blue};
display:flex; align-items:center; gap:10px;
}
.hb-section-head-en::before { content:''; display:inline-block; width:8px; height:8px; border-radius:50%; background:${hbcp.blue}; }
.hb-section-head-jp { font-family:${fontJP}; font-weight:500; font-size:32px; letter-spacing:-.01em; color:${hbcp.ink}; }
/* News */
.hb-news-row {
display:grid; grid-template-columns: 110px 110px 1fr 100px 24px; gap:24px;
padding:16px 0; border-bottom:1px solid ${hbcp.line};
align-items:center; text-decoration:none; color:${hbcp.ink};
transition: padding-left .35s ${ease}, background .35s ${ease};
}
.hb-news-row:hover { padding-left:14px; background:${hbcp.blueGhost}; }
.hb-label {
display:inline-flex; align-items:center; height:22px; padding:0 10px;
font-family:${fontENSans}; font-size:10px; font-weight:500; letter-spacing:.18em;
border:1px solid ${hbcp.ink}; color:${hbcp.ink}; line-height:1;
}
.hb-label-blue { background:${hbcp.blue}; color:#fff; border-color:${hbcp.blue}; }
.hb-label-fill { background:${hbcp.ink}; color:#fff; border-color:${hbcp.ink}; }
.hb-label-ghost { background:transparent; color:${hbcp.ink}; }
.hb-label-warm { background:${hbcp.paperWarm}; color:${hbcp.ink}; border-color:${hbcp.line}; }
/* Service block */
.hb-svc-block {
display:grid; grid-template-columns: 100px 1fr auto;
gap:48px; padding:32px 0; border-bottom:1px solid ${hbcp.ink};
align-items:flex-start; cursor:pointer; text-decoration:none; color:inherit;
transition: padding-left .4s ${ease};
}
.hb-svc-block:hover { padding-left:18px; }
.hb-svc-num {
font-family:${fontEN}; font-style:italic; font-weight:300; font-size:56px;
color:${hbcp.blue}; line-height:.9;
}
/* Big Pickup */
.hb-pickup-card {
position:relative; display:block; text-decoration:none; color:${hbcp.ink};
background:${hbcp.white}; border:1px solid ${hbcp.line}; padding:32px;
aspect-ratio: 4/3.4; overflow:hidden;
transition: transform .45s ${ease}, border-color .35s ${ease}, background .35s ${ease};
}
.hb-pickup-card:hover { transform: translateY(-4px); border-color:${hbcp.ink}; }
.hb-pickup-card.fill { background:${hbcp.blue}; color:#fff; border-color:${hbcp.blue}; }
.hb-pickup-card.fill:hover { background:${hbcp.blueDeep}; border-color:${hbcp.blueDeep}; }
.hb-pickup-card.dark { background:${hbcp.ink}; color:#fff; border-color:${hbcp.ink}; }
/* CTA */
.hb-cta {
position:relative; display:inline-flex; align-items:center; gap:14px; padding:18px 32px;
background:${hbcp.ink}; color:#fff; text-decoration:none; border-radius:999px; overflow:hidden;
font-family:${fontENSans}; font-size:13px; font-weight:500; letter-spacing:.04em;
}
.hb-cta::before { content:''; position:absolute; inset:0; background:${hbcp.blue}; transform:translateY(101%); transition:transform .5s ${ease}; border-radius:999px; }
.hb-cta:hover::before { transform:translateY(0); }
.hb-cta > * { position:relative; z-index:1; }
.hb-cta-outline { background:transparent; color:${hbcp.ink}; border:1px solid ${hbcp.ink}; }
.hb-cta-outline::before { background:${hbcp.ink}; }
.hb-cta-outline:hover { color:#fff; }
/* Marquee */
@keyframes hb-marquee { from {transform:translateX(0);} to {transform:translateX(-50%);} }
.hb-marquee { display:flex; gap:64px; animation: hb-marquee 38s linear infinite; }
`;
function HBChars({ text, delay=0, weight }) {
const lines = String(text).split('\n');
let total = 0;
return (
{lines.map((line, li) => (
{Array.from(line).map((c, i) => {
const span = (
{c===' ' ? '\u00A0' : c}
);
total++;
return span;
})}
))}
);
}
function HBLogo({ height=32, light=false }) {
return ;
}
// =====================================================
// PC HEADER — クリックでスライド開閉する全幅ドロワー
// =====================================================
// 本番 hatenabase.jp の実ナビをそのまま再現。リンクはすべて公式ページへ向ける。
// HB_BASE: ホスト判定で本番/ローカル/ngrok 自動切替え。
// - hatenabase.jp → 'https://hatenabase.jp'
// - hatenahp-v2.local:10028 / *.ngrok-free.dev / *.local 等
// → 現在の origin を使う(ローカル内回遊に閉じる)
const HB_BASE = (function(){
try {
var h = window.location.hostname;
if (/(^|\.)hatenabase\.jp$/.test(h)) return 'https://hatenabase.jp';
return window.location.origin;
} catch (e) {
return '';
}
})();
const HB_WANTEDLY = 'https://www.wantedly.com/companies/company_2336297/projects';
// 採用ポジションの単一ソース(page-recruit.jsx と共有)
// 増減時はここだけ編集すれば、トップ/採用ページ両方の表示が連動する。
const HOME_POSITIONS = [
{ dept:'DX', title:'kintoneコンサルタント', type:'正社員', loc:'東京 / リモート可' },
{ dept:'DX', title:'kintoneアプリ開発エンジニア', type:'正社員', loc:'東京 / リモート可' },
{ dept:'AI', title:'生成AI業務適用 PM', type:'正社員', loc:'東京' },
{ dept:'FINANCE', title:'会計コンサルタント / 公認会計士', type:'正社員', loc:'東京' },
{ dept:'CONTENT', title:'編集ディレクター', type:'正社員', loc:'東京 / リモート可' },
{ dept:'CORP', title:'採用担当', type:'正社員', loc:'東京' },
{ dept:'INTERN', title:'長期インターン (DX/Content/BI)', type:'インターン', loc:'東京' },
];
window.HB_POSITIONS = HOME_POSITIONS;
const HB_NAV = [
{ en:'Service', jp:'事業・サービス', href:`${HB_BASE}/hatena-dx`, items:[
{t:'Hatena,DX.', s:'DXシステム導入・BPRシステム導入支援', href:`${HB_BASE}/hatena-dx`},
{t:'Hatena,Content.', s:'DX・AI人材育成/クラウド会計人材の育成', href:`${HB_BASE}/hatena-content`},
{t:'Hatena,BI.', s:'経理業務改善・DX支援会計コンサル', href:`${HB_BASE}/hatena-bi`},
]},
{ en:'Achievements', jp:'導入事例・実績', href:`${HB_BASE}/achievements` },
{ en:'News', jp:'お知らせ', href:`${HB_BASE}/news` },
{ en:'Blog', jp:'ブログ', href:`${HB_BASE}/blog` },
{ en:'About', jp:'私たちについて', href:`${HB_BASE}/about-us` },
{ en:'Recruit', jp:'採用情報', href:`${HB_BASE}/recruit`, items:[
{t:'採用情報トップ', s:'Careers', href:`${HB_BASE}/recruit`},
{t:'一般採用', s:'Wantedly', href:HB_WANTEDLY},
{t:'新卒採用・インターン採用', s:'Wantedly Newgrad', href:`${HB_WANTEDLY}/newgrad`},
]},
];
function HBHeader() {
const [open, setOpen] = React.useState(null); // null | nav-en (PCドロップダウン)
const [mbOpen, setMbOpen] = React.useState(false); // モバイルドロワー
// 現在地判定: 各 NAV item の href のパス部分が pathname に prefix で含まれていれば active。
// 例: pathname=/news/ → m.href=…/news が match。/blog/{slug}/ → m.href=…/blog も match。
const currentPath = (typeof window !== 'undefined' && window.location && window.location.pathname) || '/';
function isNavActive ( m ) {
if ( ! m || ! m.href ) return false;
let path = '';
try { path = new URL( m.href, 'http://x' ).pathname; } catch(e){ return false; }
if ( ! path || path === '/' ) return currentPath === '/';
// パス末尾 / を整形してから前方一致
const norm = ( p ) => ( p.endsWith('/') ? p : p + '/' );
return norm( currentPath ).startsWith( norm( path ) );
}
// モバイル時はスクロールロック
React.useEffect(() => {
if (mbOpen) {
const prev = document.body.style.overflow;
document.body.style.overflow = 'hidden';
return () => { document.body.style.overflow = prev; };
}
}, [mbOpen]);
// 親 wrapper の transform: scale() スコープから抜けるため createPortal で body 直下にマウント
// → position:fixed が viewport 基準で動作し、PC でもスクロール時にヘッダー常時固定
const headerNode = (
<>