/* HMU HR Portal — 共通パーツ（ヘッダー／ヒーロー／ビジョン／3つのつながる） */
const { useState, useEffect, useRef } = React;
const HR = window.HMU_HR;
const HRD_PUB = (l) => (l || []).filter((x) => x.on !== false);

function Logo({ light }) {
  return (
    <div style={{ display:'flex', alignItems:'center', gap:11 }}>
      <div style={{ width:38, height:38, borderRadius:10, background:'#fff', border:light?'1px solid rgba(255,255,255,.25)':'1px solid var(--line)', display:'flex', alignItems:'center', justifyContent:'center', overflow:'hidden', flexShrink:0 }}>
        <img src="uploads/logo.png" alt="兵庫医科大学" style={{ width:29, height:29, objectFit:'contain', display:'block' }} />
      </div>
      <div>
        <div className="disp" style={{ fontWeight:900, fontSize:15.5, lineHeight:1.15, letterSpacing:'.02em', color: light?'#fff':'var(--ink)' }}>人事部ポータル</div>
        <div className="num" style={{ fontSize:9.5, fontWeight:700, letterSpacing:'.14em', color: light?'rgba(255,255,255,.55)':'var(--faint)' }}>HMU HUMAN RESOURCES</div>
      </div>
    </div>
  );
}

/* つながりを可視化する背景（ノード＋線） */
function ConnectCanvas({ motion = true, opacity = .5, rgb = '200,242,94', strength = 1 }) {
  const ref = useRef(null);
  useEffect(() => {
    const cv = ref.current; if (!cv) return;
    const ctx = cv.getContext('2d');
    let raf, w = 0, h = 0, pts = [];
    const dpr = Math.min(window.devicePixelRatio || 1, 2);
    function init() {
      w = cv.clientWidth; h = cv.clientHeight;
      cv.width = w * dpr; cv.height = h * dpr; ctx.setTransform(dpr,0,0,dpr,0,0);
      const n = Math.max(28, Math.min(64, Math.round(w * h / 22000)));
      pts = Array.from({ length:n }, () => ({ x:Math.random()*w, y:Math.random()*h, vx:(Math.random()-.5)*.22, vy:(Math.random()-.5)*.22, r:Math.random()*1.6+1 }));
    }
    function frame() {
      ctx.clearRect(0,0,w,h);
      pts.forEach(p => { if (motion) { p.x+=p.vx; p.y+=p.vy; if(p.x<0||p.x>w)p.vx*=-1; if(p.y<0||p.y>h)p.vy*=-1; } });
      for (let i=0;i<pts.length;i++) for (let j=i+1;j<pts.length;j++) {
        const a=pts[i], b=pts[j], dx=a.x-b.x, dy=a.y-b.y, d=Math.hypot(dx,dy);
        if (d < 150) { ctx.strokeStyle = `rgba(${rgb},${(1-d/150)*.3*strength})`; ctx.lineWidth=.7; ctx.beginPath(); ctx.moveTo(a.x,a.y); ctx.lineTo(b.x,b.y); ctx.stroke(); }
      }
      pts.forEach(p => { ctx.fillStyle=`rgba(${rgb},${.75*strength})`; ctx.beginPath(); ctx.arc(p.x,p.y,p.r,0,7); ctx.fill(); });
      raf = requestAnimationFrame(frame);
    }
    init(); frame();
    const ro = new ResizeObserver(init); ro.observe(cv);
    return () => { cancelAnimationFrame(raf); ro.disconnect(); };
  }, [motion, rgb, strength]);
  return <canvas ref={ref} style={{ position:'absolute', inset:0, width:'100%', height:'100%', opacity, pointerEvents:'none' }}></canvas>;
}

/* カーソルに追従する波紋（ヒーロー用） */
function RippleLayer({ rgb = '27,107,84', max = 0.5 }) {
  const ref = useRef(null);
  useEffect(() => {
    const cv = ref.current; if (!cv) return;
    const host = cv.parentElement, ctx = cv.getContext('2d');
    const dpr = Math.min(window.devicePixelRatio || 1, 2);
    let raf, w = 0, h = 0, waves = [], last = 0, hover = null;
    function size() { w = cv.clientWidth; h = cv.clientHeight; cv.width = w*dpr; cv.height = h*dpr; ctx.setTransform(dpr,0,0,dpr,0,0); }
    function add(x, y, strong) { waves.push({ x, y, t: 0, life: strong ? 1.5 : 1.1, r0: strong ? 12 : 6, sp: strong ? 340 : 210 }); if (waves.length > 26) waves.shift(); }
    function onMove(e) {
      const r = host.getBoundingClientRect();
      const x = e.clientX - r.left, y = e.clientY - r.top;
      hover = { x, y };
      const d = Math.hypot(x - last.x || 0, y - last.y || 0);
      if (!last || d > 34) { add(x, y, false); last = { x, y }; }
    }
    function onDown(e) { const r = host.getBoundingClientRect(); add(e.clientX - r.left, e.clientY - r.top, true); }
    function onLeave() { hover = null; }
    function frame() {
      ctx.clearRect(0,0,w,h);
      if (hover) {
        const g = ctx.createRadialGradient(hover.x, hover.y, 0, hover.x, hover.y, 190);
        g.addColorStop(0, `rgba(${rgb},${max*0.34})`); g.addColorStop(1, `rgba(${rgb},0)`);
        ctx.fillStyle = g; ctx.fillRect(0,0,w,h);
      }
      waves = waves.filter(v => v.t < v.life);
      waves.forEach(v => {
        v.t += 0.016;
        const k = v.t / v.life, r = v.r0 + v.sp * k, a = (1 - k) ** 2 * max;
        ctx.strokeStyle = `rgba(${rgb},${a})`; ctx.lineWidth = 2.4 * (1 - k) + 0.5;
        ctx.beginPath(); ctx.arc(v.x, v.y, r, 0, 7); ctx.stroke();
        ctx.strokeStyle = `rgba(${rgb},${a*0.45})`; ctx.lineWidth = 1;
        ctx.beginPath(); ctx.arc(v.x, v.y, r*0.66, 0, 7); ctx.stroke();
      });
      raf = requestAnimationFrame(frame);
    }
    size(); frame();
    host.addEventListener('pointermove', onMove);
    host.addEventListener('pointerdown', onDown);
    host.addEventListener('pointerleave', onLeave);
    const ro = new ResizeObserver(size); ro.observe(cv);
    return () => { cancelAnimationFrame(raf); ro.disconnect(); host.removeEventListener('pointermove', onMove); host.removeEventListener('pointerdown', onDown); host.removeEventListener('pointerleave', onLeave); };
  }, [rgb, max]);
  return <div className="ripple-layer"><canvas ref={ref}></canvas></div>;
}

/* ヒーロー写真：複数枚をクロスフェードで切替 */
function HeroPhotos({ images, image, sec = 7, motion = true }) {
  const list = (Array.isArray(images) && images.length ? images : [image]).filter(Boolean);
  const [i, setI] = useState(0);
  useEffect(() => {
    if (list.length < 2 || !motion) return;
    const ms = Math.max(2, Number(sec) || 7) * 1000;
    const id = setInterval(() => setI(v => (v + 1) % list.length), ms);
    return () => clearInterval(id);
  }, [list.length, sec, motion]);
  useEffect(() => { if (i >= list.length) setI(0); }, [list.length, i]);
  return (
    <React.Fragment>
      {list.map((src, n) => (
        <div key={src + n} className={'hero-photo hero-slide' + (motion ? ' kenburns' : '') + (n === i ? ' on' : '')}
          style={{ backgroundImage: `url("${src}")` }}></div>
      ))}
    </React.Fragment>
  );
}

function AlertBar({ alert }) {
  if (!alert || !alert.enabled) return null;
  const crit = alert.level === 'critical';
  return (
    <div style={{ background: crit ? 'var(--red)' : 'var(--green)', color:'#fff', padding:'10px 20px', display:'flex', alignItems:'center', gap:12, justifyContent:'center', flexWrap:'wrap' }}>
      <span className="num" style={{ fontSize:10, fontWeight:800, letterSpacing:'.1em', background:'rgba(255,255,255,.22)', color:'#fff', borderRadius:99, padding:'3px 10px' }}>{crit ? 'URGENT' : 'NEWS'}</span>
      <a href={alert.link} style={{ color:'#fff', fontSize:13, fontWeight:500, lineHeight:1.5 }}>{alert.text}</a>
    </div>
  );
}

const NAV = [['お知らせ','#news'],['手続き・様式','guides.html'],['研修・行事','#events'],['よくある質問','#faq'],['声を届ける','#voice'],['これからの人事部','vision.html'],['標語公募','vision.html#slogan']];
const NAV_PLAN = [['ビジョン','#vision'],['3つのつながる','#pillars'],['施策・工程','#roadmap'],['標語公募','#slogan'],['応募の流れ','#flow'],['ポータルトップ','index.html']];

function Header({ nav = NAV, home = '#top' }) {
  return (
    <header style={{ position:'sticky', top:0, zIndex:100, background:'rgba(250,249,245,.9)', backdropFilter:'blur(12px)', borderBottom:'1px solid var(--line)' }}>
      <div style={{ maxWidth:1280, margin:'0 auto', padding:'11px 26px', display:'flex', alignItems:'center', gap:22 }}>
        <a href={home} style={{ flexShrink:0 }}><Logo /></a>
        <nav className="nav-links" style={{ display:'flex', gap:2, flex:1, justifyContent:'center' }}>
          {nav.map(([l,h]) => (
            <a key={h} href={h} className="navlink" style={{ padding:'8px 11px', borderRadius:8, fontSize:12.5, fontWeight:600, color:'var(--sub)', whiteSpace:'nowrap' }}>{l}</a>
          ))}
        </nav>
        <div style={{ display:'flex', alignItems:'center', gap:9, flexShrink:0 }}>
          <a href="vision.html#slogan" className="btn-dark" style={{ padding:'9px 16px', borderRadius:99, fontSize:12.5, fontWeight:800, whiteSpace:'nowrap' }}>標語を応募</a>
          <a href="cms.html" style={{ padding:'9px 14px', borderRadius:99, border:'1.5px solid var(--line)', fontSize:12, fontWeight:700, color:'var(--sub)', whiteSpace:'nowrap' }}>CMS管理</a>
        </div>
      </div>
    </header>
  );
}

/* ── ヒーロー：公募モード ／ 標語決定モード ── */
function Hero({ hero, motion }) {
  const c = hero.campaign, s = hero.slogan;
  const campaign = hero.mode !== 'slogan';
  return (
    <section id="top" className="hero" style={{ position:'relative', overflow:'hidden', background:'#fff', color:'var(--ink)' }}>
      <HeroPhotos images={hero.images} image={hero.image} sec={hero.slideSec} motion={motion} />
      <div className="hero-photo-fade"></div>
      <ConnectCanvas motion={motion} rgb="27,107,84" opacity={.4} strength={.9} />
      {motion ? <RippleLayer rgb="27,107,84" max={.5} /> : null}
      <div className="hero-inner" style={{ position:'relative', maxWidth:1280, margin:'0 auto', padding:'clamp(56px,7vw,96px) 26px clamp(44px,5vw,64px)' }}>
        {campaign ? (
          <div className="hero-col" style={{ maxWidth:940 }}>
            <div className="num hero-kicker" style={{ display:'inline-flex', alignItems:'center', gap:10, fontSize:11, fontWeight:800, letterSpacing:'.18em', color:'var(--green-deep)', background:'rgba(255,255,255,.8)', border:'1.5px solid var(--green)', borderRadius:99, padding:'6px 14px', marginBottom:26 }}>
              <span style={{ width:6, height:6, borderRadius:99, background:'var(--green)' }}></span>{c.kicker}
            </div>
            <h1 className="disp hero-h1" style={{ fontWeight:900, lineHeight:1.08, letterSpacing:'-.01em', margin:'0 0 22px' }}>
              <span style={{ display:'block', color:'var(--faint)' }}>{c.lead}</span>
              <span style={{ display:'block' }}>{c.headline}</span>
            </h1>
            <p className="hero-sub" style={{ maxWidth:640, color:'var(--sub)', lineHeight:1.95, margin:'0 0 30px', textWrap:'pretty' }}>{c.sub}</p>
            <div style={{ display:'flex', flexWrap:'wrap', gap:12, marginBottom:34 }}>
              <a href={c.ctaUrl} className="btn-dark" style={{ padding:'15px 30px', borderRadius:99, fontSize:14.5, fontWeight:900 }}>{c.ctaLabel} →</a>
              <a href={c.subCtaUrl} style={{ padding:'15px 26px', borderRadius:99, border:'1.5px solid var(--ink)', background:'rgba(255,255,255,.7)', color:'var(--ink)', fontSize:13.5, fontWeight:700 }}>{c.subCtaLabel}</a>
            </div>
            <div className="hero-meta" style={{ display:'flex', flexWrap:'wrap', gap:'14px 40px', paddingTop:24, borderTop:'1px solid var(--line)' }}>
              {[['募集期間', c.period],['決定', c.decide],['応募条件', c.note]].map(([k,v]) => (
                <div key={k}>
                  <div className="num" style={{ fontSize:10, fontWeight:800, letterSpacing:'.14em', color:'var(--green)', marginBottom:6 }}>{k.toUpperCase()}</div>
                  <div style={{ fontSize:13, fontWeight:700, color:'var(--ink)' }}>{v}</div>
                </div>
              ))}
            </div>
          </div>
        ) : (
          <div className="hero-col" style={{ maxWidth:1000 }}>
            <div className="num" style={{ fontSize:11, fontWeight:800, letterSpacing:'.2em', color:'var(--green)', marginBottom:26 }}>OUR SLOGAN — 教職員の公募により決定</div>
            <h1 className="disp hero-slogan" style={{ fontWeight:900, lineHeight:1.02, letterSpacing:'-.02em', margin:'0 0 18px' }}>{s.text}</h1>
            <div style={{ fontSize:14, fontWeight:700, color:'var(--green)', letterSpacing:'.08em', marginBottom:26 }}>{s.reading}</div>
            <p className="hero-sub" style={{ maxWidth:680, color:'var(--sub)', lineHeight:1.9, margin:'0 0 30px', fontWeight:600, textWrap:'pretty' }}>{s.tagline}</p>
            <div className="hero-meta" style={{ display:'flex', flexWrap:'wrap', gap:'8px 28px', paddingTop:22, borderTop:'1px solid var(--line)', fontSize:12.5, color:'var(--faint)' }}>
              <span>{s.credit}</span><span>{s.author}</span>
            </div>
          </div>
        )}
      </div>
    </section>
  );
}

/* ヒーロー直下：人事の入口（クイックリンク） */
function QuickBar({ links, portalUrl = 'https://jinji-portal.pages.dev/' }) {
  return (
    <section style={{ background:'#fff', color:'var(--ink)', borderBottom:'1px solid var(--line)' }}>
      <div style={{ maxWidth:1280, margin:'0 auto', padding:'0 26px' }}>
        <div style={{ display:'flex', alignItems:'center', gap:12, padding:'13px 0', borderBottom:'1px solid var(--line)', flexWrap:'wrap' }}>
          <span className="num" style={{ fontSize:10, fontWeight:800, letterSpacing:'.16em', color:'var(--green)' }}>HR SYSTEMS</span>
          <span style={{ fontSize:12, color:'var(--sub)', lineHeight:1.7 }}>申請・勤怠・給与などの各種システムは「人事ポータル」に集約されています（将来的に本サイトへ統合予定）。</span>
          <a href={portalUrl} target="_blank" rel="noopener" style={{ marginLeft:'auto', fontSize:12, fontWeight:800, color:'var(--green)', whiteSpace:'nowrap' }}>人事システムポータルを開く ↗</a>
        </div>
        <div className="qbar" style={{ display:'grid', gridTemplateColumns:'repeat(8,1fr)' }}>
          {HRD_PUB(links).map(q => (
            <a key={q.id} href={q.url} target={q.ext ? '_blank' : undefined} rel={q.ext ? 'noopener' : undefined} className="qcell" style={{ padding:'20px 14px', color:'var(--ink)', display:'flex', flexDirection:'column', gap:5, borderRight:'1px solid var(--line)' }}>
              <span style={{ fontSize:13, fontWeight:800, display:'flex', alignItems:'center', gap:5 }}>{q.label}{q.ext ? <span className="num" style={{ fontSize:9.5, opacity:.45 }}>↗</span> : null}</span>
              <span style={{ fontSize:10.5, color:'var(--faint)' }}>{q.sub}</span>
            </a>
          ))}
        </div>
      </div>
    </section>
  );
}

/* これからの人事部（事業計画パージへの導線） */
function PlanPromo({ pillars, vision, url = 'vision.html' }) {
  return (
    <section style={{ background:'var(--green-tint)', borderBottom:'1px solid var(--line)' }}>
      <div className="wrap promo-grid" style={{ padding:'clamp(30px,3.4vw,44px) 26px', display:'grid', gridTemplateColumns:'1fr 1.15fr', gap:'clamp(24px,3vw,52px)', alignItems:'center' }}>
        <div>
          <div className="num" style={{ fontSize:10, fontWeight:800, letterSpacing:'.18em', color:'var(--green)', marginBottom:11 }}>OUR PLAN 2026</div>
          <h2 className="disp" style={{ fontSize:'clamp(19px,2.1vw,26px)', fontWeight:900, lineHeight:1.5, margin:'0 0 10px', textWrap:'pretty' }}>これからの人事部、これからの法人。</h2>
          <p style={{ fontSize:12.5, color:'var(--sub)', lineHeight:1.9, margin:'0 0 18px', maxWidth:420, textWrap:'pretty' }}>{vision.statement}</p>
          <a href={url} className="btn-dark" style={{ display:'inline-block', padding:'12px 24px', borderRadius:99, fontSize:13, fontWeight:800 }}>事業計画・組織風土を見る →</a>
        </div>
        <div className="promo-cards" style={{ display:'grid', gridTemplateColumns:'repeat(3,1fr)', gap:10 }}>
          {pillars.map(p => (
            <a key={p.id} href={url + '#pillars'} className="card hoverable" style={{ padding:'16px 16px', color:'var(--ink)', display:'flex', flexDirection:'column', gap:8 }}>
              <span className="num" style={{ fontSize:19, fontWeight:800, color:'var(--green)', lineHeight:1 }}>{p.no}</span>
              <span style={{ fontSize:12.5, fontWeight:800, lineHeight:1.6, textWrap:'pretty' }}>{p.title}</span>
            </a>
          ))}
        </div>
      </div>
    </section>
  );
}

function SectionHead({ id, ja, en, note, action }) {
  return (
    <div style={{ display:'flex', alignItems:'flex-end', gap:16, marginBottom:26, flexWrap:'wrap' }}>
      <div>
        <div className="num" style={{ fontSize:10.5, fontWeight:800, letterSpacing:'.18em', color:'var(--green)', marginBottom:9 }}>{en}</div>
        <h2 id={id} className="disp" style={{ fontSize:'clamp(22px,2.4vw,30px)', fontWeight:900, letterSpacing:'-.01em', margin:0, scrollMarginTop:88 }}>{ja}</h2>
      </div>
      {note ? <p style={{ fontSize:13, color:'var(--sub)', margin:0, maxWidth:460, lineHeight:1.8, paddingBottom:3 }}>{note}</p> : null}
      {action ? <a href={action[1]} style={{ marginLeft:'auto', fontSize:12.5, fontWeight:800, paddingBottom:5 }}>{action[0]} →</a> : null}
    </div>
  );
}

/* ── ビジョン ── */
function Vision({ vision }) {
  return (
    <section className="wrap" style={{ padding:'clamp(60px,7vw,96px) 26px' }}>
      <div className="vision-grid" style={{ display:'grid', gridTemplateColumns:'1fr', gap:'clamp(24px,3vw,40px)', alignItems:'start', maxWidth:900 }}>
        <div>
          <div className="num" style={{ fontSize:10.5, fontWeight:800, letterSpacing:'.18em', color:'var(--green)', marginBottom:14 }}>OUR VISION</div>
          <div style={{ fontSize:12.5, fontWeight:700, color:'var(--sub)', marginBottom:18 }}>{vision.label}</div>
          <h2 id="vision" className="disp" style={{ fontSize:'clamp(24px,3.1vw,40px)', fontWeight:900, lineHeight:1.45, letterSpacing:'-.01em', margin:'0 0 26px', scrollMarginTop:88, textWrap:'pretty' }}>
            {vision.statement}
          </h2>
          <p style={{ fontSize:14, color:'var(--sub)', lineHeight:2, margin:'0 0 24px', maxWidth:640, textWrap:'pretty' }}>{vision.body}</p>
        </div>
      </div>
    </section>
  );
}

/* ── 3つのつながる ── */
function Pillars({ pillars }) {
  const [open, setOpen] = useState('p1');
  return (
    <section style={{ background:'var(--paper2)', color:'var(--ink)', position:'relative', overflow:'hidden', borderTop:'1px solid var(--line)', borderBottom:'1px solid var(--line)' }}>
      <ConnectCanvas motion={true} rgb="27,107,84" opacity={.3} strength={.9} />
      <div className="wrap" style={{ position:'relative', padding:'clamp(60px,7vw,96px) 26px' }}>
        <div style={{ marginBottom:36 }}>
          <div className="num" style={{ fontSize:10.5, fontWeight:800, letterSpacing:'.18em', color:'var(--green)', marginBottom:12 }}>THREE CONNECTIONS</div>
          <h2 id="pillars" className="disp" style={{ fontSize:'clamp(24px,3vw,38px)', fontWeight:900, letterSpacing:'-.01em', margin:'0 0 14px', scrollMarginTop:88 }}>「つながる」を、3つの柱で進めます</h2>
          <p style={{ fontSize:13.5, color:'var(--sub)', lineHeight:1.9, maxWidth:620, margin:0 }}>目指す組織風土・職場環境の実現に向け、人事部は以下の3つの柱に沿って改革を進めます。</p>
        </div>
        <div className="pillar-grid" style={{ display:'grid', gridTemplateColumns:'repeat(3,1fr)', gap:14 }}>
          {pillars.map(p => {
            const on = open === p.id;
            return (
              <div key={p.id} onMouseEnter={() => setOpen(p.id)} style={{ background: on?'var(--green-tint)':'#fff', border:`1px solid ${on?'var(--green)':'var(--line)'}`, borderRadius:18, padding:'clamp(24px,2.4vw,32px)', transition:'background .25s,border-color .25s', cursor:'default' }}>
                <div className="num" style={{ fontSize:34, fontWeight:800, color: on?'var(--green)':'#D7D9D3', lineHeight:1, marginBottom:18, transition:'color .25s' }}>{p.no}</div>
                <h3 className="disp" style={{ fontSize:'clamp(16px,1.5vw,19px)', fontWeight:900, lineHeight:1.5, margin:'0 0 8px' }}>{p.title}</h3>
                <div className="num" style={{ fontSize:9.5, fontWeight:700, letterSpacing:'.14em', color:'var(--faint)', marginBottom:20 }}>{p.en}</div>
                <ul style={{ listStyle:'none', margin:0, padding:0, display:'flex', flexDirection:'column', gap:11 }}>
                  {p.items.map((it,i) => (
                    <li key={i} style={{ display:'flex', gap:10, fontSize:12.5, lineHeight:1.75, color:'var(--sub)' }}>
                      <span style={{ color:'var(--green)', flexShrink:0, fontWeight:800 }}>／</span>{it}
                    </li>
                  ))}
                </ul>
              </div>
            );
          })}
        </div>
      </div>
    </section>
  );
}

Object.assign(window, { Logo, HeroPhotos, ConnectCanvas, RippleLayer, AlertBar, Header, Hero, QuickBar, PlanPromo, SectionHead, Vision, Pillars, NAV, NAV_PLAN });
