의약품 산업지원 포털 디자인 시스템

실제 포털 페이지에서 사용되는 컴포넌트·토큰·레이아웃 패턴을 한 곳에 정리한 문서입니다.
페이지별로 등장하는 클래스와 마크업을 그대로 반영해, 신규 화면을 만들 때 바로 복사·재사용할 수 있도록 구성했습니다.

Foundation

컬러 · 타이포 · 간격 · 라운드 · 그림자

모든 토큰은 common/css/portal.css:root에서 정의됩니다. 액센트는 브랜드 Blue (#1a6bff)로 통일하고, 심사자 면만 Navy를 씁니다. 폰트는 SUIT(common/fonts/suit.css) · 아이콘은 Material Symbols Outlined(common/fonts/material-symbols.css) 로컬입니다.

Brand · 액센트 스와치
brand-50
#eff6ff
brand-100
#dbeafe
brand-200
#bfdbfe
brand
#1a6bff
brand-600
#2563eb
auth-portal-900
#003E89
auth-gun-900
#0a1628
중립 · 텍스트
card
#ffffff
bg
#f8fafc
bg-alt
#f1f5f9
border
#e2e8f0
dim
#94a3b8
muted
#64748b
text
#0f172a
상태색 (자가검증 결과·뱃지)
ok / 적정
#10B981
ok-strong
#15803D
bad / 미흡
#dc2626
warn / 확인요
#d97706
violet (BV)
#7C3AED
타이포 스케일
fs-display의약품 산업지원 포털
SVL 히어로 (clamp 38–64px)
fs-h1 / 800의약품 산업지원 포털
page-hero · 40px
fs-h2 / 800단계별 서비스 안내
section title · 26px
fs-h3 / 700chat-head__title
20px
fs-h4 / 700검증 항목 카드 제목
17px
fs-body본문 기본 — 행간 1.6
15px
fs-sm보조 본문 · field hint
13.5px
fs-xs메타 · pager · breadcrumb
12px
fs-2xs · eyebrowSUPPORTED DOCUMENTS
11px · svl-section-eyebrow
/* :root (portal.css 발췌) */
:root{
  --font: "SUIT", "Apple SD Gothic Neo", "맑은 고딕", system-ui, sans-serif;
  --fs-display: clamp(38px, 5.5vw, 64px);
  --fs-h1: 40px; --fs-h2: 26px;
  --fs-h3: 20px; --fs-h4: 17px;
  --fs-body: 15px; --fs-sm: 13.5px;
  --fs-xs: 12px; --fs-2xs: 11px;
  --tracking-tight: -.8px;
  --tracking-eyebrow: 2.5px;
}
간격 · 라운드 · 그림자

간격은 --s1…--s12 (4·8·12·16·20·24·32·40·48px), 라운드는 --r-xs/sm/md/lg/xl/pill, 그림자는 --sh-1/2/3·--sh-glow·--sh-glow-brand를 씁니다.

--r-sm 8px
--r-md 12px
--r-lg 16px
--r-xl 20px
--r-pill
sh-1
sh-2
sh-3
sh-glow-brand
Shell

GNB · 푸터 · 본문 컨테이너

GNB는 <portal-gnb></portal-gnb> 커스텀 엘리먼트(portal.js가 마크업 주입), 푸터는 <portal-footer></portal-footer> 또는 본 페이지처럼 <footer class="footer">를 직접 씁니다. 랜딩2/3은 body.landing2-body 안에 .landing2-ambient 배경 레이어를 추가합니다.

기본 페이지 골격
<!doctype html>
<html lang="ko" data-page="portal_xxx">
<head><link rel="stylesheet" href="common/fonts/suit.css" />
  <link rel="stylesheet" href="common/fonts/material-symbols.css" />
  <link rel="stylesheet" href="common/css/portal.css" /></head>
<body>
  <a class="skip" href="#main">본문 바로가기</a>
  <portal-gnb></portal-gnb>
  <main id="main"></main>
  <portal-footer></portal-footer>
  <script defer src="common/js/portal.js"></script>
</body></html>
브레드크럼 (.breadcrumb)
<nav class="breadcrumb" aria-label="위치">
  <a href="portal_landing.html"></a>
  <span aria-hidden="true"><span class="icon icon--line">chevron_right</span></span>
  <span aria-current="page">현재 페이지</span>
</nav>
데이터 안내 박스 (.ds-demo-note)

시연시 모든 데이터는 가상으로 구현된 데이터로 진행됩니다. 실제 데이터와는 다릅니다.

<div class="ds-demo-note" role="note">
  <span class="icon">info</span>
  <div><p class="ds-demo-note__p"></p></div>
</div>
Headers

랜딩 히어로 · 서브페이지 헤더 · chat-head

랜딩(portal_landing.html)은 다크 .hero + 캔버스 dots, 서브페이지는 .data-head > .container.chat-head의 브레드크럼·아이콘·제목 구성을 씁니다. portal_mypage.html은 같은 영역에 .page-head·.page-kicker를 추가합니다.

서브페이지 헤더 (.data-head + .chat-head)

나의 자가검증 현황

제출서류의 AI 자가검증 결과와 보완 가이드를 확인합니다.

<section class="data-head" aria-labelledby="page-title">
  <div class="container chat-head">
    <nav class="breadcrumb"></nav>
    <div class="chat-head__row">
      <span class="chat-head__icon"><span class="icon">fact_check</span></span>
      <div>
        <h1 class="chat-head__title" id="page-title">제목</h1>
        <p class="chat-head__sub">설명</p>
      </div>
    </div>
  </div>
</section>
page-head · page-kicker (현황 화면)
<div class="page-head">
  <div>
    <p class="page-kicker">마이페이지 · 자가검증</p>
    <h1 id="page-title">제출자료 자가검증 현황</h1>
    <p>설명…</p>
  </div>
</div>
랜딩 히어로 (.hero)

portal_landing.html 전용 다크 히어로. 배경 레이어 4종(.hero__bg · .hero__aurora · .hero__glow · canvas#hero-dots)이 겹쳐집니다. 제목 줄바꿈 <br class="hero__title-br">는 좁은 폭에서만 노출됩니다.

<section class="hero">
  <div class="hero__bg" aria-hidden="true"></div>
  <div class="hero__aurora"><span></span><span></span><span></span></div>
  <div class="hero__glow"></div>
  <canvas class="hero__dots" id="hero-dots"></canvas>
  <div class="hero__content" data-reveal>
    <h1 class="hero__title">의약품 심사·행정을<br class="hero__title-br"><em>AI</em>가 함께합니다</h1>
    <p class="hero__desc"></p>
    <div class="hero__actions"></div>
  </div>
</section>
섹션 헤더 (.sh)

4대 핵심 AI 서비스

의약품 산업지원 포털의 AI 서비스를 선택하여 이용해 보세요.

<header class="sh" data-reveal>
  <h2 class="sh__title">제목</h2>
  <p class="sh__desc">설명</p>
</header>
portal_login

로그인 · 포털(Blue) / 심사자(Navy)

body.login-bodydata-login-tab="portal"|"review"로 면을 구분합니다. 상단 행은 .login-top-row(돌아가기 + 모드 탭), 카드는 .login-card--portal / .login-card--review로 좌측 브랜드 열과 우측 폼 패널(.login-panel)이 한 카드에 들어갑니다.

모드 탭 (.login-mode)
<div class="login-mode-bar">
  <div class="login-mode" role="tablist" aria-label="로그인 유형">
    <button class="login-mode__btn" role="tab" aria-selected="true" aria-controls="panel-portal-m">포털 로그인</button>
    <button class="login-mode__btn" role="tab" aria-selected="false" aria-controls="panel-review-m">심사자 전용</button>
  </div>
</div>
로그인 카드 본체
<div id="panel-portal-m" class="login-card login-card--portal" role="tabpanel">
  <div class="login-brand login-brand--portal">
    <div class="login-brand__inner">
      <h1 class="login-brand__headline">의약품 산업지원 포털</h1>
      <div class="login-shield">
        <span class="icon">verified_user</span>
        <p><strong>대국민·산업 지원 서비스입니다</strong></p>
      </div>
      <div class="login-status">
        <div class="login-status__bar"><span>System status</span><em>ACTIVE</em></div>
        <div class="login-status__track"><div class="login-status__fill"></div></div>
      </div>
    </div>
  </div>
  <div class="login-panel">
    <h2 class="login-panel__title">로그인</h2>
    <p class="login-panel__sub"></p>
    <form class="js-login-form" novalidate>
      <div class="login-field">
        <label for="uid-portal-m">아이디</label>
        <div class="login-input-wrap">
          <span class="icon icon--line">person</span>
          <input id="uid-portal-m" name="uid" type="text" autocomplete="username" />
        </div>
      </div>
      <div class="login-field">
        <label for="pw-portal-m">비밀번호</label>
        <div class="login-input-wrap login-input-wrap--has-toggle">
          <span class="icon icon--line">lock</span>
          <input type="password" id="pw-portal-m" name="password" />
          <button type="button" class="login-pw-toggle" aria-pressed="false">
            <span class="icon icon--line">visibility</span>
          </button>
        </div>
      </div>
      <div class="login-row"><label><input type="checkbox" name="keep" /> 로그인 상태 유지</label></div>
      <button type="submit" class="login-submit">로그인</button>
    </form>
    <div class="login-links"><a>아이디 찾기</a><strong><a>회원가입</a></strong></div>
  </div>
</div>
심사자 면 (.login-card--review / .login-brand--reviewer)

필드 라벨이 영문(User ID / Password)이고, 폼 하단에 .login-notice(info 아이콘 + 보안 안내) 한 줄이 들어갑니다. "ID 저장" 체크박스와 "보안 토큰 재발급" 링크는 한 줄(.login-row)에 양 끝 정렬됩니다.

Buttons & Tags

버튼 · 칩 · 뱃지 · 태그

사이즈 스케일 (.btn--xs · .btn--sm · .btn--md · .btn--lg · .btn--xl · .btn--xxl)

크기 modifier 조합 시 항상 .btn .btn--{variant} .btn--{size} 순서로 작성. md가 기본값이라 별도 클래스 없이 .btn만 사용해도 같음. 표는 11px / 13px / 14px / 15px / 16px / 18px 글자 크기에 매핑됩니다.

<!-- 가장 작은 보조 액션 (테이블 행 안 등) -->
<button class="btn btn--primary btn--xs">편집</button>

<!-- 툴바 · 카드 액션 (가장 자주 쓰임) -->
<button class="btn btn--primary btn--sm">저장하기</button>

<!-- 본문 기본 액션 -->
<button class="btn btn--primary">제출하기</button>     <!-- = btn--md -->

<!-- 폼 제출 / 다이얼로그 주 액션 -->
<button class="btn btn--primary btn--lg">로그인</button>

<!-- 랜딩 히어로 CTA -->
<a class="btn btn--primary btn--xl" href="…">지금 시작하기</a>

<!-- 마케팅 페이지 / 빅 CTA -->
<a class="btn btn--primary btn--xxl"><span class="icon">auto_awesome</span>AI 자가검증 시작하기</a>
변형 × 사이즈 매트릭스

사용 가능한 색상 변형: .btn--primary / .btn--secondary / .btn--outline / .btn--line / .btn--ghost. 테이블의 각 행이 동일 사이즈(SM)에서의 변형 비교입니다.

<!-- ── 1행: SM 사이즈 × 5변형 ── -->
<button class="btn btn--primary btn--sm"><span class="icon">arrow_forward</span>Primary</button>
<button class="btn btn--secondary btn--sm">Secondary</button>
<button class="btn btn--outline btn--sm">Outline</button>
<button class="btn btn--line btn--sm">Line</button>
<button class="btn btn--ghost btn--sm">Ghost</button>

<!-- ── 2행: MD(기본) 사이즈 × 5변형 — 사이즈 클래스 생략 가능 ── -->
<button class="btn btn--primary"><span class="icon">arrow_forward</span>Primary</button>
<button class="btn btn--secondary">Secondary</button>
<button class="btn btn--outline">Outline</button>
<button class="btn btn--line">Line</button>
<button class="btn btn--ghost">Ghost</button>

<!-- ── 3행: LG 사이즈 × 5변형 ── -->
<button class="btn btn--primary btn--lg"><span class="icon">arrow_forward</span>Primary</button>
<button class="btn btn--secondary btn--lg">Secondary</button>
<button class="btn btn--outline btn--lg">Outline</button>
<button class="btn btn--line btn--lg">Line</button>
<button class="btn btn--ghost btn--lg">Ghost</button>

<!-- 변형 의미 -->
<!-- Primary: 기본 액션. 페이지·다이얼로그·카드당 1개 권장 -->
<!-- Secondary: 보조 액션. 흰 배경 + 테두리 -->
<!-- Outline: 브랜드 컬러 강조 보조 액션 -->
<!-- Line: 단순 테두리 보조 (toolbar refresh 등) -->
<!-- Ghost: 텍스트만 (메뉴·내비) -->
아이콘 전용 (.btn--icon) · 블록(.btn--block) · 비활성
<!-- 아이콘 전용: aria-label 필수 -->
<button class="btn btn--secondary btn--icon btn--sm" aria-label="편집">
  <span class="icon">edit</span>
</button>

<!-- 폼·로그인 등 풀폭 액션 -->
<button class="btn btn--primary btn--block btn--lg">로그인</button>

<!-- 비활성: 둘 중 어느 쪽이든 OK (disabled 우선 권장) -->
<button class="btn btn--primary" disabled>처리 중</button>
<a class="btn btn--primary is-disabled" aria-disabled="true">대기</a>
랜딩 전용 CTA (.svl-btn-* / .landing2-btn--*)

자가검증 랜딩 SVL은 .svl-btn-primary · .svl-btn-ghost를, 타일형 메인은 .landing2-btn.landing2-btn--primary · .landing2-btn--ghost를 씁니다.

<a class="svl-btn-primary" href="portal_01_selfverify.html"><span class="icon">description</span>검증 시작하기</a>
<a class="svl-btn-ghost" href="portal_mypage.html"><span class="icon">monitoring</span>나의 자가검증 현황</a>
<a class="landing2-btn landing2-btn--primary">서비스 시작하기</a>
칩 사이즈 스케일 (.chip--xs · .chip--sm · .chip--md · .chip--lg)

MD가 기본값. min-height는 18 / 22 / 24 / 30px, font-size는 10 / 11 / 12 / 13px로 4단계 명확히 구분. 실 사이트 매핑 — XS: 표 행 안 inline 카운터(향후) · SM: 알림·서브 메타 · MD: 자가검증 결과 행 · LG: 모달 헤더 강조.

XS · 적정 SM · 적정 MD · 적정 (기본) LG · 적정
<span class="chip chip--ok chip--xs">적정</span>
<span class="chip chip--ok chip--sm">적정</span>
<span class="chip chip--ok">적정</span>            <!-- = chip--md -->
<span class="chip chip--ok chip--lg">적정</span>
칩 상태 변형 — 실 사이트 사용 매핑

.chip--ok(녹색·적정/완료) · .chip--bad(빨강·미흡/부적정/반려) · .chip--warn(주황·확인요) · .chip--info(파랑·진행중) · .chip--neutral(회색·미신청/—) · .chip--brand(브랜드·신청완료).

자가검증 결과 행 (적정 / 미흡 / 확인요)

적정 미흡 부적정 확인요

민원 신청 상태 (마이페이지 테이블)

미신청 신청완료

검증 진행 (자가검증 / 검토)

진행 중 완료 보완 필요
<!-- ── 자가검증 결과 행 (chip--md, 기본 사이즈) ── -->
<!--    portal.js renderVerifyResultStackHtml 가 그리는 200건 항목별 결과 -->
<span class="chip chip--ok chip--md">적정</span>
<span class="chip chip--bad chip--md">미흡</span>
<span class="chip chip--bad chip--md">부적정</span>
<span class="chip chip--warn chip--md">확인요</span>

<!-- ── 마이페이지 민원신청 컬럼 (chip--sm, 표 행 안에 들어가므로 작게) ── -->
<!--    portal_mypage.html — table.u-table-list 의 마지막 컬럼 -->
<span class="chip chip--neutral chip--sm">미신청</span>
<span class="chip chip--brand chip--sm">신청완료</span>

<!-- ── 자가검증 진행 상태 (chip--sm, 표 행 안) ── -->
<span class="chip chip--info chip--sm">진행중</span>
<span class="chip chip--ok chip--sm">완료</span>
<span class="chip chip--bad chip--sm">보완 필요</span>
<span class="chip chip--neutral chip--sm"></span>
뱃지 사이즈 스케일 (.badge--xs · .badge--sm · .badge--md · .badge--lg)

min-height 16 / 18 / 22 / 28px, font-size 9 / 10 / 11 / 13px. 칩보다 한 단계 작아서 메타 라벨·태그 용도.

XS · 9px SM · 10px MD · 11px (기본) LG · 13px
<span class="badge badge--brand badge--xs">NEW</span>
<span class="badge badge--brand badge--sm">법령·가이드</span>
<span class="badge badge--brand">인증된 서비스</span>
<span class="badge badge--brand badge--lg"><span class="icon">verified</span>인증완료</span>
뱃지 컬러 변형 — 실 사이트 사용 매핑

브랜드(--brand) · 청록(--teal) · 자주(--purple) · 초록(--green) · 호박(--amber) · 장미(--rose) · 회색(--gray) · 자동저장(--save).

verified인증된 서비스 법령·가이드 로그인 필요 데이터셋 검토 대기 처리 지연 미정 cloud_done자동 저장됨
<!-- ── 위 미리보기는 모두 badge--md (기본 사이즈, 클래스 생략 가능) ── -->
<span class="badge badge--brand badge--md"><span class="icon">verified</span>인증된 서비스</span>
<span class="badge badge--teal badge--md">법령·가이드</span>
<span class="badge badge--purple badge--md">로그인 필요</span>
<span class="badge badge--green badge--md">데이터셋</span>
<span class="badge badge--amber badge--md">검토 대기</span>
<span class="badge badge--rose badge--md">처리 지연</span>
<span class="badge badge--gray badge--md">미정</span>
<span class="badge badge--save badge--md"><span class="icon">cloud_done</span>자동 저장됨</span>

<!-- 출처 매핑 -->
<!-- badge--teal/purple/green : portal_landing*.html 서비스 카드 라벨 -->
<!-- badge--save              : portal_01b_review_editor.html 자동저장 인디케이터 -->
태그 (.tag) — 카테고리·키워드 단순 라벨
Text · ko Benchmark CTD m3
<span class="tag">Text · ko</span>
<span class="tag">Benchmark</span>
선택 chip (.choice-chip) / 추천 chip (.rev-db-chip)
  • 품목허가대장
  • 검토서 메타DB
Forms

폼 · 인풋 · 드롭존 · 라디오 카드

기본 필드 (.field)
자가검증 라디오 카드 (.radio-card)

portal_01_selfverify.html Step 1에서 4종 서류 유형 선택용. input[type=radio]를 시각적으로 숨기고, 카드 자체가 라벨이 됩니다.

<label class="radio-card">
  <input type="radio" name="doc-type" value="bio-plan" />
  <span class="radio-card__indicator"></span>
  <span class="radio-card__icon"><span class="icon">biotech</span></span>
  <span class="radio-card__title">생물학적 동등성 시험계획서</span>
  <span class="radio-card__desc"></span>
</label>
드롭존 (.dropzone)
upload_file
파일을 여기에 끌어다 놓거나 선택하세요

PDF · XLSX · DOCX (파일당 최대 100MB · 최대 12개)

<div class="dropzone" id="dropzone" tabindex="0" role="button">
  <div class="dropzone__icon"><span class="icon">upload_file</span></div>
  <div class="dropzone__title">파일을 여기에 끌어다 놓거나 선택하세요</div>
  <p class="dropzone__meta">PDF · XLSX · DOCX (최대 100MB · 12개)</p>
  <input type="file" id="file-input" multiple accept=".pdf,.docx,.xlsx" style="display:none" />
  <button type="button" class="btn btn--secondary" id="btn-browse"><span class="icon">upload_file</span> 파일 찾기 및 선택</button>
  <div id="file-pill-wrap"></div>
</div>
마이페이지 필터바 (.mypg-filter) — 실제 portal_mypage.html에서 추출

한 줄에 검색2 + 일자범위 + 셀렉트3 + 초기화/조회 버튼이 배치되는 가로형 필터바. .mypg-filter__row가 flex 컨테이너이며 자식 컨트롤들이 wrap되며 채워집니다.

검증일자 ~
<div class="mypg-filter">
  <div class="mypg-filter__row">
    <label class="mypg-filter__search">
      <input type="search" id="q-id" placeholder="검증일련번호 검색" />
    </label>
    <label class="mypg-filter__search">
      <input type="search" id="q-file" placeholder="파일명 검색" />
    </label>
    <div class="mypg-filter__date">
      <span class="mypg-filter__date-label">검증일자</span>
      <input type="date" id="f-date-from" />
      <span class="mypg-filter__date-sep">~</span>
      <input type="date" id="f-date-to" />
    </div>
    <select id="f-status"><option value="">진행상태 전체</option></select>
    <select id="f-outcome"><option value="">결과구분 전체</option></select>
    <select id="f-civil"><option value="">신청여부 전체</option></select>
    <button class="btn btn--outline btn--sm" id="btn-filter-reset">초기화</button>
    <button class="btn btn--primary btn--sm" id="btn-filter-search"><span class="icon">search</span>조회</button>
  </div>
</div>
레거시 필터(.toolbar) — 자가검증 진입 페이지 등 보조 화면용
add신규 검증 신청
Tables

목록 테이블 · 페이지네이션

모든 목록 테이블은 .panel > .table-wrap > table.u-table-list 구조입니다. 빈 상태는 p.empty, 페이저는 nav.pager를 씁니다.

자가검증 현황 테이블 (6열) — portal_mypage.html과 1:1 일치

실 화면 6열: 검증일련번호 · 검증일자 · 파일명 · 검증진행상태 · 검증결과구분 · 민원신청여부. 헤더 배경은 navy(--brand-900 계열) · 흰 글씨. 행 클릭 시 상세결과 모달(#modal-verify-detail) 오픈. 상태/결과/신청여부 컬럼은 .chip--sm(작은 사이즈) 사용.

검증일련번호검증일자파일명검증진행상태검증결과구분민원신청여부
S-2026-TDVZUE 2026-03-30 의료기기_SW_Verification_Report.pdf 완료 미흡 (3/200) 미신청
S-2026-WLTNVG 2026-03-28 GMP_적합판정서_2026_v1.2.pdf 완료 적정 (180/200) 미신청
S-2026-AQYPWP 2026-03-26 포장재_적합성_시험성적서.pdf 완료 적정 (180/200) 신청완료
S-2026-FSOWSW 2026-03-24 Dissolution_Profile_Table.xlsx 진행중 미신청
<!-- portal_mypage.html ─ 실제 마크업 그대로 -->
<div class="panel">
  <div class="table-wrap">
    <table class="u-table-list">
      <thead>
        <tr>
          <th>검증일련번호</th>
          <th>검증일자</th>
          <th>파일명</th>
          <th>검증진행상태</th>
          <th>검증결과구분</th>
          <th>민원신청여부</th>
        </tr>
      </thead>
      <tbody id="tbody">
        <!-- 행은 portal.js에서 동적 렌더 (DB.submissions 기반) -->
        <tr>
          <td>S-2026-TDVZUE</td>
          <td>2026-03-30</td>
          <td>의료기기_SW_Verification_Report.pdf</td>
          <td><span class="chip chip--ok chip--sm">완료</span></td>
          <td><span class="chip chip--bad chip--sm">미흡 (3/200)</span></td>
          <td><span class="chip chip--neutral chip--sm">미신청</span></td>
        </tr>
      </tbody>
    </table>
  </div>
  <p class="empty" id="empty" style="display:none">조건에 맞는 검증 건이 없습니다.</p>
  <nav class="pager" id="pager" hidden></nav>
</div>
페이지네이션 (.pager)
<nav class="pager" id="pager" aria-label="검증 목록 페이지">
  <p class="pager__meta">총 N건…</p>
  <div class="pager__controls">
    <button class="pager__btn pager__btn--icon" id="pager-first"><span class="icon">first_page</span></button>
    <button id="pager-prev"></button>
    <ul class="pager__list" id="pager-list" role="list"></ul>
    <button id="pager-next"></button>
    <button id="pager-last"></button>
  </div>
</nav>
Service & Feature

서비스 카드 (.svc) · 피처 (.feat)

portal_landing.html에서 사용. 4대 서비스 카드는 .svc-carousel > .svc-carousel__track.u-grid-4 안에 .svc를 배치하고, 변형(--teal · --purple · --green)으로 카드 톤만 다르게 합니다. 피처는 .feat-carousel > .u-grid-3입니다.

4대 서비스 카드
<a class="svc svc--teal" href="portal_02_info_chat.html">
  <span class="svc__bg-icon icon" aria-hidden="true">auto_stories</span>
  <span class="svc__icon"><span class="icon">auto_stories</span></span>
  <h3 class="svc__title">정보제공 AI</h3>
  <p class="svc__desc"></p>
  <div class="svc__footer">
    <span class="badge badge--teal">법령·가이드</span>
    <span class="icon icon--line svc__arrow">arrow_forward</span>
  </div>
</a>
피처 카드 (.feat)
auto_awesome

LLM 기반 대화형 AI

자연어 질문에 규정·법령 근거를 즉시 안내합니다.

document_scanner

문서 자동 검증

업로드 서류의 적합성을 자동 점검합니다.

shield_lock

보안 및 개인정보 보호

처리 후 문서·개인정보를 즉시 삭제합니다.

portal_01_selfverify_landing

자가검증 랜딩 (SVL)

body.svl-page 전용 다크 히어로 + 라이트 본문 구성. 히어로 SVG 애니메이션, 통계 카운터, 4종 서류 카드, 4단계 프로세스, 핵심 기능 그리드, CTA로 이어집니다.

섹션 헤더 패턴 (.svl-section-head)

Supported Documents

검증 가능한 서류 4종

허가 신청 시 보완 요청이 잦은 핵심 서류별 맞춤 검증을 제공합니다.

<div class="svl-section-head" data-reveal>
  <p class="svl-section-eyebrow">Supported Documents</p>
  <h2 class="svl-section-title">검증 가능한 서류 4종</h2>
  <p class="svl-section-desc"></p>
</div>
4단계 프로세스 (.svl-process)
<div class="svl-process" role="list">
  <div class="svl-step" role="listitem" data-reveal>
    <div class="svl-step__icon">
      <span class="svl-step__num-badge">01</span>
      <svg viewBox="0 0 48 48"></svg>
    </div>
    <p class="svl-step__title">유형 선택</p>
    <p class="svl-step__desc">검증할 서류 유형을 선택</p>
  </div>
  <!-- 02 / 03 / 04 동일 구조 -->
</div>
핵심 기능 그리드 (.svl-feature-grid)
<section class="svl-section svl-section--dark">
  <div class="svl-inner">
    <div class="svl-feature-grid">
      <div class="svl-feature-item">
        <div class="svl-feature-item__icon"><span class="icon">format_list_bulleted</span></div>
        <div>
          <p class="svl-feature-item__title">필수 항목 누락 감지</p>
          <p class="svl-feature-item__desc"></p>
        </div>
      </div>
    </div>
  </div>
</section>
CTA 블록 (.svl-cta + .svl-notice)
<div class="svl-cta">
  <p class="svl-cta__eyebrow">GET STARTED</p>
  <h2 class="svl-cta__title">제출 전, 지금 점검해 보세요</h2>
  <p class="svl-cta__sub"></p>
  <div class="svl-cta__actions">
    <a class="svl-btn-primary">검증 시작하기</a>
    <a class="svl-btn-ghost svl-btn-ghost--light">나의 자가검증 현황</a>
  </div>
  <div class="svl-notice">
    <span class="icon svl-notice__icon">info</span>
    <div>
      <p class="svl-notice__title">서비스 유의사항</p>
      <p class="svl-notice__body"></p>
    </div>
  </div>
</div>
portal_landing2 / 3

타일형 랜딩

body.landing2-body + .landing2-ambient(배경 블롭·그리드). 4개 타일이 .landing2-grid에 들어가고, 각 타일은 호버/포커스 시 하위 링크(.landing2-subs)가 펼쳐집니다. portal_landing3.htmlhtml.landing3 data-theme="light"로 같은 컴포넌트를 라이트 톤으로 덮어씁니다.

앰비언트 배경 + 히어로
<div class="landing2-ambient" aria-hidden="true">
  <span class="landing2-ambient__blob landing2-ambient__blob--1"></span>
  <span class="landing2-ambient__blob landing2-ambient__blob--2"></span>
  <span class="landing2-ambient__blob landing2-ambient__blob--3"></span>
  <span class="landing2-ambient__grid"></span>
</div>
<header class="landing2-hero">
  <h1 class="landing2-hero__title">의약품 산업지원 포털</h1>
  <div class="landing2-hero__cta">
    <a class="landing2-btn landing2-btn--primary">서비스 시작하기</a>
    <a class="landing2-btn landing2-btn--ghost">로그인</a>
  </div>
</header>
타일 (.landing2-tile) + 하위 링크
<div class="landing2-grid" role="list">
  <article class="landing2-tile landing2-tile--sv" tabindex="0" role="listitem">
    <div class="landing2-tile__bg"></div>
    <span class="landing2-tile__float"><span class="icon">verified_user</span></span>
    <div class="landing2-tile__deco">
      <span class="landing2-chip"><span class="icon">biotech</span>생동성 시험</span>
      <span class="landing2-chip landing2-chip--muted"></span>
    </div>
    <div class="landing2-tile__inner">
      <h2 class="landing2-tile__title">제출서류 자가검증 AI</h2>
      <p class="landing2-tile__lead"></p>
      <div class="landing2-subs">
        <a class="landing2-link" href="portal_01_selfverify.html?doc=bio-plan">
          <span class="icon">biotech</span>
          <span class="landing2-link__txt">생물학적 동등성 시험계획서 검증</span>
          <span class="icon landing2-link__go">arrow_forward</span>
        </a>
      </div>
    </div>
  </article>
  <!-- --info / --civil / --data 동일 패턴 -->
</div>
<p class="landing2-hint">배너에 마우스를 올리거나…</p>
portal_01_selfverify

자가검증 위저드 · 진행/완료 모달

2열 셸(.sv-layout) — 좌측 절차 안내 아코디언(.sv-proc.sv-proc-acc) + 우측 본문(.sv-main). 스텝퍼(.wizard-stepper)·스텝 패널(.step-panel)·진행 모달(.modal-card--sv-steps)·접수 완료 모달(.modal-card--async-done)·결과 모달(.modal-card--sv-result)이 한 페이지 안에 함께 있습니다.

스텝퍼 (.wizard-stepper)
check
자가검증 AI 유형 선택
2
제출서류 파일 업로드 및 자가검증
<div class="wizard-stepper" id="wizard-stepper">
  <div class="wizard-stepper__item is-active" data-ws="1">
    <div class="wizard-stepper__circle">1</div>
    <div class="wizard-stepper__label">자가검증 AI 유형 선택</div>
  </div>
  <div class="wizard-stepper__item" data-ws="2"></div>
</div>
2열 셸 + 스텝 패널 + 액션 행
<section class="container section sv-section">
  <div class="sv-layout">
    <aside class="sv-proc">
      <details class="sv-proc-acc">
        <summary class="sv-proc-acc__summary">
          <span class="sv-proc-acc__summary-text">자가검증 절차</span>
          <span class="icon sv-proc-acc__chev">expand_more</span>
        </summary>
        <div class="sv-proc-acc__panel">
          <h2 class="sv-proc__title">제출서류 자가검증 절차 안내</h2>
          <ol class="sv-proc__list">
            <li><span class="sv-proc__num">1</span> 검증할 제출서류에 맞는 …</li>
          </ol>
          <p class="sv-proc__note">※ 검증 완료시 …</p>
        </div>
      </details>
      <div class="sv-proc__foot">
        <a class="btn btn--secondary btn--sm" href="portal_mypage.html">나의 자가검증 현황 열기</a>
      </div>
    </aside>
    <div class="sv-main">
      <div class="wizard-stepper"></div>
      <div class="step-panel is-active" id="step-1">
        <header class="step-head"><div>
          <span class="eyebrow">Step 1</span>
          <h2 class="step-head__title">유형을 선택하세요</h2>
          <p class="step-head__desc"></p>
        </div></header>
        <form id="verify-form">
          <div class="u-grid-2" role="radiogroup"></div>
        </form>
      </div>
      <div class="step-panel" id="step-2">
        <header class="step-head"><div>
          <p class="step-head__picked-type">선택 유형: <strong></strong></p>
          <span class="eyebrow">Step 2</span></div></header>
        <div class="dropzone"></div>
        <div class="action-row">
          <button class="btn btn--secondary btn--outline" id="btn-back-2">이전으로</button>
          <div class="action-row__end">
            <button class="btn btn--outline btn--sm" id="btn-reset-files">초기화</button>
            <button class="btn btn--primary btn--xl" id="btn-start-verify">AI 자가검증 시작</button>
          </div>
        </div>
      </div>
    </div>
  </div>
</section>
진행/완료 모달 (.modal-card--sv-steps)

한 카드 안에 진행 패널(#prog-running-panel)과 완료 패널(#prog-complete-panel hidden)이 함께 들어갑니다. 상단 .prog-flow-type으로 선택 유형을 보여주고, 진행 시 .sv-step__bar·.sv-step__notes·.sv-step__eta를, 완료 시 .sv-step__result(결과 dl)·.sv-step__complete-desc를 노출합니다.

<div class="modal-backdrop" id="modal-progress">
  <div class="modal-card modal-card--sv-steps">
    <p class="prog-flow-type">선택 유형: <strong>생물학적 동등성 시험계획서</strong></p>
    <div id="prog-running-panel">
      <h3 class="sv-step__title">제출서류 파일 업로드 중</h3>
      <p class="sv-step__sub"></p>
      <div class="sv-step__bar"><div class="sv-step__bar-fill"></div></div>
      <ul class="sv-step__notes"><li></li></ul>
      <p class="sv-step__eta">예상완료시간: 약 30분 <span class="sv-step__eta-note">※ …</span></p>
      <div class="sv-step__foot"><button class="btn btn--outline">닫기</button></div>
    </div>
    <div id="prog-complete-panel" hidden>
      <h3 class="sv-step__title sv-step__title--done">자가검증 완료</h3>
      <dl class="sv-step__result">
        <div class="sv-step__result-row"><dt>검증일련번호</dt><dd></dd></div></dl>
      <p class="sv-step__complete-desc"></p>
      <div class="sv-step__foot"><a class="btn btn--primary" href="portal_mypage.html">나의 자가검증 현황 열기</a></div>
    </div>
  </div>
</div>
접수 완료 모달 (.modal-card--async-done)
<div class="modal-backdrop" id="modal-async-done">
  <div class="modal-card modal-card--async-done">
    <button class="modal-card__close" id="btn-async-x"><span class="icon">close</span></button>
    <h3 class="modal-card__title">접수가 완료되었습니다</h3>
    <div class="modal-card__body">
      <p class="modal-async__lead"><strong>첨부 묶음</strong> 검증 요청이 접수되었습니다.</p>
      <p><strong>12</strong>분 후 결과 확인이 가능…</p>
      <p class="modal-async__fine">이 창을 닫으셔도 됩니다…</p>
    </div>
    <div class="modal-actions">
      <button class="btn btn--outline">확인 · 닫기</button>
      <a class="btn btn--primary">마이페이지에서 확인</a>
    </div>
  </div>
</div>
portal_mypage / portal_01a_verify_status

마이페이지 · 검증 상세결과

마이페이지(portal_mypage)는 .mypg-filter + .u-table-list(6열) + #modal-verify-detail.modal-card--mypg-detail의 조합입니다. 자가검증 현황(portal_01a_verify_status)은 같은 패턴에 우측 aside.panel.detail.verify-detail-source 숨김 패널을 두고, #modal-verify-detail.modal-card--detail-mobile.modal-card--verify-detail로 상세를 띄웁니다.

상세 모달 셸 (.modal-card--mypg-detail)
<div class="modal-backdrop" id="modal-verify-detail" role="dialog" aria-modal="true" aria-labelledby="mypg-detail-title" aria-hidden="true">
  <div class="modal-card modal-card--wide modal-card--mypg-detail">
    <h2 class="mypg-detail-modal__title" id="mypg-detail-title">자가검증 상세결과</h2>
    <div id="detail-modal-slot" class="detail-modal-slot"></div>
    <div class="mypg-detail-modal__foot">
      <button class="btn btn--outline" id="btn-detail-close">닫기</button>
    </div>
  </div>
</div>
검증 현황 우측 디테일 패널 (.detail.verify-detail-source)
<aside class="panel detail verify-detail-source" id="detail" aria-hidden="true">
  <div class="empty" id="detail-placeholder">목록에서 항목을 선택하세요.</div>
  <div id="detail-body" style="display:none">
    <div class="detail__head">
      <div>
        <h2 id="d-title">자가검증 결과</h2>
        <p class="detail__file-line" id="d-file-line"></p>
      </div>
      <button class="btn btn--line" id="btn-close-detail"><span class="icon">close</span></button>
    </div>
    <div id="d-verify-root" class="detail-verify-root"></div>
    <div class="detail__foot-actions">
      <button class="btn btn--primary" id="d-dl-verify"><span class="icon">download</span>검증결과 다운로드</button>
      <a class="btn btn--line" id="d-reverify-link"><span class="icon">upload</span>보완 자료 재검증</a>
      <a class="btn btn--outline" id="d-editor-link"><span class="icon">edit_document</span>AI 검토서 편집기</a>
    </div>
  </div>
</aside>
portal_02_info_chat / portal_03_civil_initial

정보제공 · 민원지원 챗 셸

두 챗은 동일한 셸을 공유합니다 — div.portal-flow-chat.portal-flow-chat--embed 안에 section.container.chat-area > .chat-wrap이 들어가고, 상단 고정 분야 패널(.civil-panel-fixed) → 스크롤 영역(.chat-scroll) → 입력창(.compose) 순으로 배치됩니다.

고정 분야 패널 (.civil-panel-fixed + .choice-list)

민원 챗에서는 「다빈도 민원신청 추천」 + <hr class="civil-group-divider"> + 「전자증명서 발급」 두 그룹이 한 패널 안에 들어갑니다. 그룹 헤더는 .civil-group-head(아이콘 + 제목 + 보조 라벨), 항목은 button.choice입니다.

다빈도 민원신청 추천 (최근 3개월 및 전년 동기)

전자증명서 발급 서비스
메시지 turn · bubble · compose
<div class="chat-scroll" id="info-chat-scroll" aria-live="polite">
  <div class="turn">
    <span class="avatar avatar--ai" aria-hidden="true"><span class="icon">smart_toy</span></span>
    <div class="turn__body">
      <div class="turn__meta"><strong>정보제공 AI</strong></div>
      <div class="bubble bubble--ai"><p>안녕하세요…</p></div>
    </div>
  </div>
  <!-- 내 메시지(우측): 아바타·이름 없이 정렬만 -->
  <div class="turn turn--user"><div class="turn__body"><div class="bubble bubble--user"></div></div></div>
</div>
<div class="compose">
  <div class="compose__row">
    <div class="compose__input">
      <span class="icon">edit_note</span>
      <input id="info-chat-input" type="text" placeholder="질문 내용 입력" />
    </div>
    <button class="compose__send" id="info-chat-send" aria-label="보내기"><span class="icon">send</span></button>
  </div>
  <p class="compose__hint"><span class="icon">info</span>AI가 제공하는 정보는 참고용입니다.</p>
</div>
portal_01b_review_editor

AI 검토서 편집기 (rev-*)

body.rev-body · 3열 워크스페이스 (.rev-workspace) — 좌(제출서류·최근문서) / 중(탭별 작업 영역) / 우(챗봇). 가운데 영역은 6개 탭(편집기·허가DB·요약·번역·비교·비전AI)을 .rev-rail + .rev-pane으로 전환합니다.

루트 골격
<body class="rev-body">
  <main id="main" class="rev-main">
    <div class="rev-workspace" id="rev-workspace">
      <aside class="rev-left" id="rev-left"></aside>
      <div class="rev-gutter rev-gutter--l" id="rev-gutter-l" role="separator" tabindex="0"></div>
      <section class="rev-center"></section>
      <div class="rev-gutter rev-gutter--r" id="rev-gutter-r"></div>
      <aside class="rev-right" id="rev-right"></aside>
    </div>
  </main>
</body>
좌측 — 문서 탭 + 프로젝트 트리
<div class="rev-side-tabs rev-side-tabs--pill" role="tablist">
  <button class="rev-side-tab is-active" data-rev-doc-tab="sub">제출서류</button>
  <button class="rev-side-tab" data-rev-doc-tab="recent">최근문서</button>
</div>
<div class="rev-doc-pane is-active" id="rev-pane-sub">
  <div class="rev-proj-upload">
    <input type="file" id="rev-proj-upload-input" multiple />
    <button class="rev-proj-upload__hit">
      <span class="icon rev-proj-upload__ic">upload</span>
      <span class="rev-proj-upload__ttl">파일 업로드</span>
    </button>
    <p class="rev-proj-upload__help">PDF · XLSX · DOCX (최대 100MB) · 데모</p>
  </div>
  <div class="rev-proj">
    <h2 class="rev-proj__title">프로젝트 폴더</h2>
    <div class="rev-proj-tree">
      <div class="rev-proj-node">
        <button class="rev-proj-folder is-open" aria-expanded="true">
          <span class="icon rev-proj-folder__ic">folder</span>
          <span class="rev-proj-folder__name">KD-2304 신약 허가</span>
        </button>
        <div class="rev-proj-nest">
          <button class="rev-proj-file rev-proj-file--active">
            <span class="icon rev-proj-file__ic">table_chart</span>
            <span class="rev-proj-file__name">독성시험 데이터_최종.xlsx</span>
          </button>
        </div>
      </div>
    </div>
  </div>
  <h2 class="rev-h2">관련 검토서 현황</h2>
  <div class="rev-status-cards">
    <button class="rev-status-card">
      <span class="rev-dot">·</span><span class="rev-name">아스피린정 100mg</span>
      <span class="rev-chip rev-chip--ok">허가심사 완료</span>
    </button>
  </div>
  <ol class="rev-timeline">
    <li><time datetime="2026-01-13">2026. 1. 13.</time><span>안전성 데이터 보완</span></li>
  </ol>
</div>
레일 (.rev-rail) + 패널 전환
<nav class="rev-rail" role="tablist">
  <button class="rev-rail__btn rev-rail__btn--active" data-rev-tab="ed">
    <span class="icon icon--line">description</span>
    <span class="rev-rail__label">AI 검토서 편집기</span>
  </button>
  <button data-rev-tab="db">…허가DB검색…</button>
  <button data-rev-tab="sum">…내용요약…</button>
  <button data-rev-tab="tr">…다국어 번역…</button>
  <button data-rev-tab="cmp">…비교…</button>
  <button data-rev-tab="vis">…비전 AI…</button>
</nav>
<div class="rev-pane is-active" id="rev-pane-ed"><iframe src="editor/word_editor.html" class="rev-word-embed__frame"></iframe></div>
<div class="rev-pane rev-pane--db rev-tool-page" id="rev-pane-db" hidden></div>
<div class="rev-pane rev-pane--sum rev-tool-page" id="rev-pane-sum" hidden></div>
<div class="rev-pane rev-pane--tr rev-tool-page" id="rev-pane-tr" hidden></div>
<div class="rev-pane rev-pane--cmp rev-tool-page" id="rev-pane-cmp" hidden></div>
<div class="rev-pane rev-pane--vis rev-tool-page" id="rev-pane-vis" hidden></div>
탭별 헤더 패턴 (.rev-tool-page__head)
<header class="rev-tool-page__head">
  <div class="rev-tool-page__head-text">
    <h2 class="rev-tool-page__title">의약품 허가 DB 정밀 검색</h2>
    <p class="rev-tool-page__desc">품목허가대장·검토서 메타를 조회합니다.</p>
  </div>
  <button class="rev-db-ai-toggle is-on" aria-pressed="true"><span class="icon">bolt</span><span class="rev-db-ai-toggle__txt">AI 보조 검색 활성</span></button>
</header>
번역 보드 (.rev-tr-board) / 비교 (.rev-cmp-shell)
<!-- 번역: 좌 원문 / 우 번역문 -->
<div class="rev-tr-board">
  <section class="rev-tr-panel">
    <header class="rev-tr-panel__head">
      <h3 class="rev-tr-panel__title">원문</h3>
      <span class="rev-tr-badge rev-tr-badge--medical">의약품</span>
    </header>
    <textarea class="rev-tr-editor" id="rev-tr-src-editor" lang="en"></textarea>
  </section>
  <section class="rev-tr-panel">
    <header><span class="rev-tr-badge rev-tr-badge--ai"><span class="icon">auto_awesome</span>AI 번역</span></header>
    <textarea class="rev-tr-editor" id="rev-tr-tgt-editor" lang="ko"></textarea>
  </section>
</div>

<!-- 비교: 변경 요약 + 좌우 비교 본문 -->
<div class="rev-cmp-summary">
  <span class="rev-cmp-summary__total"><span class="rev-cmp-dot rev-cmp-dot--neutral"></span><strong>전체 변경</strong> 8</span>
  <span class="rev-cmp-chip rev-cmp-chip--mod">수정 3</span>
  <span class="rev-cmp-chip rev-cmp-chip--del">삭제 2</span>
  <span class="rev-cmp-chip rev-cmp-chip--add">추가 3</span>
</div>
<div class="rev-cmp-panes">
  <div class="rev-cmp-col"><div class="rev-cmp-doc"><li class="rev-cmp-li--del"></li><span class="rev-mark-mod">65</span></div></div>
  <div class="rev-cmp-col rev-cmp-col--new"><div class="rev-cmp-doc"><li class="rev-cmp-li--add"></li></div></div>
</div>
우측 챗봇 (.rev-right)
<aside class="rev-right" id="rev-right">
  <div class="rev-chat-arch">
    <div class="rev-chat-arch__logo"><span class="icon">smart_toy</span></div>
    <div class="rev-chat-arch__meta">
      <div class="rev-chat-arch__title">AI 인텔리전스 어시스턴트</div>
      <div class="rev-chat-arch__status"><span class="rev-chat-arch__dot"></span>SYSTEM ONLINE</div>
    </div>
  </div>
  <div class="rev-chat-scroll" id="rev-chat-scroll" role="log">
    <div class="rev-chat-turn rev-chat-turn--user"><div class="rev-chat-msg rev-chat-msg--user">아스피린정이 주성분인 품목</div></div>
    <div class="rev-chat-turn rev-chat-turn--ai">
      <div class="rev-chat-avatar rev-chat-avatar--ai"><span class="icon">smart_toy</span></div>
      <div class="rev-chat-msg rev-chat-msg--ai"><h3>아스피린</h3><p></p></div>
    </div>
  </div>
  <form class="rev-chat-form rev-chat-form--arch" id="rev-chat-form">
    <div class="rev-chat-bar">
      <textarea id="rev-chat-input" class="rev-chat-input rev-chat-input--bar"></textarea>
      <button class="rev-chat-icobtn rev-chat-icobtn--bar"><span class="icon">attach_file</span></button>
      <button type="submit" class="rev-chat-send-btn"><span class="icon">send</span></button>
    </div>
  </form>
</aside>
편집기 전용 자가검증 모달 (#rev-modal-sv-progress / #rev-modal-sv-result)

자가검증 페이지 모달과 동일 계열(.modal-card--progress + .modal-card--progress-live / .modal-card--sv-result)을 쓰되 ID는 충돌을 피해 rev- 접두사를 둡니다. 진행 모달은 .prog-live 안에 .prog-live__main(아이콘 + 진행바 + 기어 애니메이션)과 우측 .prog-rail(5단계 리스트)이 들어갑니다.

portal_06_data

데이터 개방 (ds-*)

상단 서브 탭(.subtabs) → 검색 바(.ds-search-bar) → 카드 그리드(.ds-card-grid) → 페이지네이션(.ds-pager) 순서. 카드와 페이지 항목은 portal.js가 채웁니다.

서브 탭 (.subtabs)
<div class="subtabs" role="tablist" aria-label="데이터 유형">
  <button role="tab" aria-pressed="true" aria-controls="ds-list" data-type="train">학습데이터</button>
  <button role="tab" aria-pressed="false" data-type="eval">평가데이터</button>
  <button role="tab" aria-pressed="false" data-type="api">API</button>
</div>
검색 바 (.ds-search-bar)
<div class="ds-search-bar" role="search">
  <label class="ds-search-bar__field ds-search-bar__field--keyword">
    <span class="icon ds-search-bar__search-ic">search</span>
    <input type="search" id="ds-q" class="ds-search-bar__input" placeholder="데이터명 또는 API명 검색" />
  </label>
  <div class="ds-search-bar__date-wrap">
    <span class="ds-search-bar__date-label">구축일자</span>
    <input type="date" id="ds-date-from" class="ds-search-bar__date" />
    <span class="ds-search-bar__date-sep">~</span>
    <input type="date" id="ds-date-to" class="ds-search-bar__date" />
  </div>
  <div class="ds-search-bar__btns">
    <button class="btn btn--line btn--sm" id="ds-reset">초기화</button>
    <button class="btn btn--primary btn--sm" id="ds-search">조회</button>
  </div>
</div>
카드 그리드 + 페이저
<div class="ds-card-grid" id="ds-list" role="list" aria-live="polite"></div>
<nav class="ds-pager" id="ds-pager" aria-label="페이지 이동"></nav>
index.html (portal_worklist)

시연용 화면 목록 (wl-*)

.page-hero + .wl-jump 점프 내비 + 섹션별 .wl-block + 카드 그리드 .wl-grid > .wl-card 구성. 미디어형 카드는 .wl-card--media로 좌측에 파비콘을 둡니다.

<section class="page-hero">
  <div class="container">
    <h1 class="page-hero__title">시연용 <em>화면·링크</em> 목록</h1>
    <p class="page-hero__desc"></p>
    <nav class="wl-jump" aria-label="섹션 바로가기">
      <a href="#wl-common">공통·입구</a></nav>
  </div>
</section>

<section id="wl-common" class="wl-block">
  <div class="wl-sec section-head">
    <span class="section-head__eyebrow">공통</span>
    <h2 class="section-head__title">공통·입구</h2>
    <p class="section-head__desc"></p>
  </div>
  <div class="wl-grid">
    <a class="wl-card" href="portal_landing.html">
      <span class="wl-card__label">일반 · 입구</span>
      <span class="wl-card__title">포털 랜딩</span>
      <span class="wl-card__meta">설명</span>
      <span class="wl-card__url">portal_landing.html</span>
    </a>
    <a class="wl-card wl-card--media" href="nedrug_local/index.html">
      <span class="wl-card__top">
        <img class="wl-card__portico" src="common/img/favicon.png" alt="" />
        <span class="wl-card__stack"></span>
      </span>
    </a>
  </div>
</section>
Iconography

아이콘 (Material Symbols)

모두 로컬 woff2 (common/fonts/material-symbols.css) 사용. <span class="icon">name</span>로 호출하며, 라인 가중치는 .icon--line을 추가합니다. 페이지별로 자주 쓰는 글리프를 함께 정리해 두었습니다.

자주 쓰는 글리프
verified_userverified_user
fact_checkfact_check
auto_storiesauto_stories
support_agentsupport_agent
datasetdataset
smart_toysmart_toy
biotechbiotech
sciencescience
vaccinesvaccines
medicationmedication
inventory_2inventory_2
upload_fileupload_file
descriptiondescription
edit_noteedit_note
edit_documentedit_document
monitoringmonitoring
restart_altrestart_alt
auto_awesomeauto_awesome
arrow_forwardarrow_forward
arrow_backarrow_back
chevron_rightchevron_right
expand_moreexpand_more
first_pagefirst_page
last_pagelast_page
refreshrefresh
addadd
closeclose
searchsearch
sendsend
attach_fileattach_file
downloaddownload
cloud_donecloud_done
savesave
folderfolder
picture_as_pdfpicture_as_pdf
table_charttable_chart
infoinfo
helphelp
verifiedverified
check_circlecheck_circle
warningwarning
personperson
badgebadge
locklock
visibilityvisibility
loginlogin
summarizesummarize
translatetranslate
compare_arrowscompare_arrows
document_scannerdocument_scanner
trending_uptrending_up
categorycategory
menu_bookmenu_book
gavelgavel
help_centerhelp_center
hourglass_tophourglass_top
Inventory

페이지 ↔ data-page

portal.jsdocument.documentElement.getAttribute("data-page") 값으로 페이지별 스크립트를 분기합니다. 새 페이지를 만들 때는 반드시 <html data-page="…">을 지정하고, 본 표에 키를 추가하세요.

파일 ↔ 루트 속성 ↔ 주요 컴포넌트
파일 data-page 주요 컴포넌트
index.html portal_worklist .page-hero · .wl-jump · .wl-block · .wl-grid · .wl-card / .wl-card--media
portal_landing.html portal_landing .hero + canvas#hero-dots · .svc-carousel · .svc (--teal/--purple/--green) · .feat-carousel · .feat
portal_landing2.html portal_landing2 .landing2-ambient · .landing2-hero · .landing2-grid · .landing2-tile (--sv/--info/--civil/--data) · .landing2-subs · .landing2-link
portal_landing3.html portal_landing3 (html.landing3 data-theme="light") landing2 컴포넌트 + 라이트 테마 오버라이드 · 하단 CTA(.landing2-hero__cta--below-grid)
portal_login.html portal_login body.login-body · data-login-tab · .login-mode-bar · .login-card--portal/--review · .login-brand--portal/--reviewer · .login-shield · .login-status · .login-panel · .login-field · .login-input-wrap · .login-pw-toggle · .login-submit · .login-links · .login-notice
portal_01_selfverify_landing.html portal_01_selfverify_landing (body.svl-page) .svl-hero + .svl-orb · .svl-hero__stats + .svl-count · .svl-doc-grid · .svl-doc-card (--blue/--violet/--green/--soft) · .svl-process · .svl-step · .svl-feature-grid · .svl-cta · .svl-notice · .svl-btn-primary/-ghost
portal_01_selfverify.html portal_01_selfverify .sv-layout · .sv-proc.sv-proc-acc · .sv-main · .wizard-stepper · .step-panel · .radio-card · .dropzone · .action-row · 모달 3종 (.modal-card--sv-steps · .modal-card--async-done · .modal-card--sv-result)
portal_mypage.html portal_01a_verify_status .data-head + .page-head · .page-kicker · .toolbar · .layout · .panel · table.u-table-list (7열) · .pager · aside.detail.verify-detail-source · .modal-card--detail-mobile.modal-card--verify-detail
portal_01b_review_editor.html portal_01b_review_editor (body.rev-body) .rev-workspace 3열 (.rev-left / .rev-center / .rev-right) · .rev-gutter--l/--r · .rev-rail 6탭 (ed/db/sum/tr/cmp/vis) · .rev-pane · .rev-proj-tree · .rev-status-cards · .rev-timeline · .rev-tr-board · .rev-cmp-shell · .rev-vis-table · .rev-chat-arch + .rev-chat-bar · #rev-modal-sv-progress · #rev-modal-sv-result · #modal-rev-base
portal_mypage.html portal_mypage .chat-head · .mypg-filter + .mypg-filter__row · .panel · table.u-table-list (6열) · .pager · .modal-card--mypg-detail + .mypg-detail-modal__title/__foot · #detail-modal-slot
portal_02_info_chat.html portal_02_info_chat .portal-flow-chat.portal-flow-chat--embed · .chat-area · .chat-wrap · .civil-panel-fixed + .civil-group-head · .choice-list + .choice · .chat-scroll · .turn + .avatar--ai + .bubble--ai · .compose + .compose__row/__input/__send/__hint
portal_03_civil_initial.html portal_03_civil_initial info_chat과 동일 셸 + .civil-group-divider · 다빈도 민원 + 전자증명서 발급 그룹
portal_04_data.html portal_06_data .subtabs (train/eval/api) · .ds-search-bar + __field/__date-wrap/__btns · .ds-card-grid · .ds-pager
portal_styleguide.html portal_styleguide 본 문서 · .sg-toc · .sg-section · .sg-block · .sg-demo · .sg-code · .sw-grid · .iconset
nedrug_local/index.html 의약품안전나라 임베드 데모 · #nedrug-chat-fab · #nedrug-ai-panel (별도 chatbot/embed-chatbot.css)
editor/word_editor.html portal_01b_review_editoriframe#rev-word-frame으로 임베드

신규 페이지 추가 시 ① <html lang="ko" data-page="고유키"> 지정 → ② 공통 에셋 3종(suit.css · material-symbols.css · portal.css) 링크 → ③ <portal-gnb> · <portal-footer> 사용 → ④ 본 문서의 해당 컴포넌트 마크업 복사 → ⑤ portal.js에 페이지별 분기 추가.

공용 토큰 사용 원칙

① 액센트는 브랜드 Blue로 통일하고, 레거시 --accent-teal/-purple/-green은 같은 값으로 매핑됩니다. ② 로그인 면만 --auth-portal-*(공식 Blue) / --auth-gun-*(Navy)으로 면을 구분합니다. ③ 상태 색은 .chip--ok/--bad/--run/--neutralverify-rv-table의 행 클래스(.is-ok/.is-warn/.is-bad)에서만 사용합니다. ④ 강조 그림자(--sh-glow-brand / --sh-glow)는 Primary 버튼·챗 전송 등 한정된 요소에만 씁니다.

/* 1) 액센트는 브랜드 Blue로 통일 */
:root{
  --brand: #1a6bff; --brand-600: #2563eb;
  --accent: var(--brand);
  --accent-600: var(--brand-600);
  --accent-bg: var(--brand-50);
  --accent-border: var(--brand-200);
}

/* 2) 로그인 면 구분 — 포털 = 공식 Blue, 심사자 = Navy */
.login-body[data-login-tab="portal"] .login-brand--portal{
  /* --auth-portal-900 / 700 / 500 그라데이션 */
}
.login-body[data-login-tab="review"] .login-brand--reviewer{
  /* --auth-gun-950 … 300 Navy 스케일 */
}

/* 3) 상태 색은 chip / verify-rv-table 행에서만 사용 */
.chip--ok      { color: #15803D; }
.chip--bad     { color: #dc2626; }
.chip--run     { color: var(--brand-600); }
.chip--neutral { color: var(--muted); }

/* 4) 강조 그림자 — Primary 버튼 / 챗 전송 등 한정 사용 */
.btn--primary  { box-shadow: var(--sh-glow-brand); }
.compose__send { box-shadow: var(--sh-glow); }
신규 페이지 보일러플레이트

가장 자주 쓰이는 “브레드크럼 + chat-head + container 본문 + 푸터” 구조입니다. 헤더 아이콘과 제목·설명만 바꿔서 시작하세요.

<!doctype html>
<html lang="ko" data-page="portal_xx_new">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
  <meta name="theme-color" content="#ffffff" />
  <title>새 페이지 — 의약품 산업지원 포털</title>
  <link rel="icon" href="common/img/favicon.png" type="image/png" />
  <link rel="stylesheet" href="common/fonts/suit.css" />
  <link rel="stylesheet" href="common/fonts/material-symbols.css" />
  <link rel="stylesheet" href="common/css/portal.css" />
</head>
<body>
  <a class="skip" href="#main">본문 바로가기</a>
  <portal-gnb></portal-gnb>
  <main id="main">
    <section class="data-head" aria-labelledby="page-title">
      <div class="container chat-head">
        <nav class="breadcrumb" aria-label="위치">
          <a href="portal_landing.html"></a>
          <span aria-hidden="true"><span class="icon icon--line">chevron_right</span></span>
          <span aria-current="page">새 페이지</span>
        </nav>
        <div class="chat-head__row" data-reveal>
          <span class="chat-head__icon" aria-hidden="true"><span class="icon">fact_check</span></span>
          <div>
            <h1 class="chat-head__title" id="page-title">새 페이지</h1>
            <p class="chat-head__sub">한 줄 설명</p>
          </div>
        </div>
      </div>
    </section>

    <div class="container" style="padding-top:var(--s6);padding-bottom:var(--s10)">
      <!-- 본문: 본 스타일가이드의 컴포넌트 섹션을 복사해 사용 -->
    </div>
  </main>
  <portal-footer></portal-footer>
  <script defer src="common/js/portal.js"></script>
</body></html>
portal_admin_dashboard

AI 심사포털 (Admin Dashboard) 컴포넌트

심사관 전용 대시보드(portal_admin_dashboard.html)에서 사용되는 컴포넌트 모음. 클래스 prefix는 .ad-*이며, 현재는 페이지 상단 <style> 블록에 스코프되어 있습니다. 다른 어드민 화면에서 재사용할 경우 해당 CSS 블록을 복사하거나 portal.css로 이전해 주세요.

상단 바 (.ad-top) — 햄버거 · 타이틀 · 사용자 · 알림

sticky 56px 헤더. 드롭다운(사용자/알림) 토글은 페이지 하단 스크립트 참고.

<header class="ad-top">
  <button class="ad-top__menu" id="ad-side-toggle" aria-label="메뉴 토글"><span class="icon icon--line">menu</span></button>
  <div class="ad-top__brand">
    <span class="ad-top__title">AI 심사포털</span>
    <span class="ad-top__chip">식품의약품안전처</span>
  </div>
  <div class="ad-top__spacer"></div>
  <div class="ad-top__user"><b>홍대식</b> | 의약품심사부 | 심사관</div>
  <!-- 사용자 / 알림 드롭다운 버튼은 .ad-top__icon-wrap 으로 감싸기 -->
</header>
좌측 사이드바 (.ad-side) — 그룹 · 라벨 · 즐겨찾기 · 뱃지
<aside class="ad-side">
  <a class="ad-side__item is-active"><span class="icon icon--line">space_dashboard</span>대시보드</a>

  <div class="ad-side__group">
    <p class="ad-side__label">AI 기본도구</p>
    <a class="ad-side__item">
      <span class="icon icon--line">search</span>AI 검색
      <span class="star is-on"></span>      <!-- 즐겨찾기 ON -->
    </a>
    <a class="ad-side__item">
      <span class="icon icon--line">folder_managed</span>검토서 관리
      <span class="badge">3</span>                <!-- 카운트 뱃지 -->
    </a>
  </div>
</aside>
상태 카드 (.ad-stat-card) — 5컬럼 그리드, 클릭 시 필터

.is-active로 선택 강조. data-filter(all/in/prog/reject/done) · data-count로 JS와 연결. 아이콘 컬러 modifier: --all(파랑) · --in(파랑) · --prog(주황) · --reject(빨강) · --done(초록).

<div class="ad-status-grid">
  <div class="ad-stat-card is-active" data-filter="all" data-count="63">
    <div class="ad-stat-card__label">전체
      <span class="ad-stat-card__icon ad-stat-card__icon--all"><span class="icon">description</span></span>
    </div>
    <div class="ad-stat-card__num">63</div>
    <div class="ad-stat-card__sub">건 담당 · 클릭해 필터</div>
  </div>
  <!-- in / prog / reject / done 카드 동일 구조 -->
</div>
검토서 테이블 (.ad-rev-table) — pill / aitag / dday

헤더는 가운데 정렬, 품목명 컬럼만 좌측 정렬. 행 단위 modifier: tr[data-status](필터 매칭) / .is-hidden(필터 결과 숨김). 상태 pill: .ad-pill--prog/in/done/reject. D-day: .ad-dday--urgent/done/rej.

<table class="ad-rev-table">
  <thead><tr>
    <th class="col-no">No</th>
    <th class="col-name">품목명 / 신청 유형</th>
    <th class="col-stat">진행상태</th>
    <th class="col-ai">AI 처리</th>
    <th class="col-d">마감</th>
  </tr></thead>
  <tbody id="ad-rev-list">
    <tr data-status="prog">
      <td class="col-no">01</td>
      <td class="col-name">트라스투주맙주 150mg
        <small>셀트리온 · <code>S-2026-KZQTPL</code> · 수입품목 허가</small>
      </td>
      <td><span class="ad-pill ad-pill--prog">작성중</span></td>
      <td><span class="ad-aitag">자가검증 92점</span></td>
      <td class="col-d"><span class="ad-dday ad-dday--urgent">D-1</span></td>
    </tr>
  </tbody>
</table>
도구 카드 — 1×6 (.ad-tools-list--six) / 2×2 (.ad-tools-list--stack)
<!-- 1×6 (의약품 AI 심사 기본도구) -->
<div class="ad-tools-list ad-tools-list--six">
  <a class="ad-tool-card" href="portal_01b_review_editor.html?tab=ed&blank=1">
    <span class="icon">description</span>
    <span class="ad-tool-card__name">AI 검토서 편집기</span>
    <span class="ad-tool-card__desc">검토서 본문 작성·편집</span>
  </a>
</div>

<!-- 2×2 row 카드 + 강조 -->
<a class="ad-tool-card ad-tool-card--row ad-tool-card--featured">
  <span class="ad-tool-card__icon-wrap"><span class="icon">auto_awesome</span></span>
  <span>
    <span class="ad-tool-card__name">자동 검토서 생성</span>
    <span class="ad-tool-card__desc">AI 초안 자동 작성</span>
  </span>
</a>
우측 위젯 (.ad-right · .ad-mini-block)

섹션 간 자동 구분선: .ad-mini-block + .ad-mini-block { border-top:1px solid var(--border); padding-top:22px; }. 컨테이너: 막대(.ad-bar) / 추이 SVG(.ad-trend) / 마감 임박(.ad-urgent-list) / 활동(.ad-activity-list).

<aside class="ad-right">
  <div class="ad-right__head"><h3>업무 현황</h3></div>

  <div class="ad-mini-block">
    <div class="ad-bar">
      <div class="ad-bar__row">
        <div class="ad-bar__top"><span>접수완료</span><b>14건</b></div>
        <div class="ad-bar__track"><div class="ad-bar__fill ad-bar__fill--in" style="width:22.2%"></div></div>
      </div>
    </div>
  </div>

  <div class="ad-mini-block"><h4>마감 임박</h4>
    <div class="ad-urgent-list">
      <div class="ad-urgent-item">
        <span class="ad-urgent-item__d">D-1</span>
        <span class="ad-urgent-item__name">트라스투주맙주 · 셀트리온</span>
      </div>
    </div>
  </div>

  <div class="ad-mini-block"><h4>최근 활동</h4>
    <div class="ad-activity-list">
      <div class="ad-activity-item">
        <span class="ad-activity-item__icon ad-activity-item__icon--ok"><span class="icon">check</span></span>
        <div class="ad-activity-item__body">
          <strong>아토르바스타틴정 20mg</strong> · LG화학 — 검토 완료
          <em>10분 전 · S-2026-ULYWTI</em>
        </div>
      </div>
    </div>
  </div>
</aside>
사용자/알림 드롭다운 (.ad-pop)

.ad-top__icon-wrap > button + .ad-pop 패턴. .is-open으로 표시. 알림 새 항목은 .ad-noti-item.is-new(파란 배경) + 제목 옆 .new-dot.

<!-- 사용자 메뉴 -->
<div class="ad-top__icon-wrap">
  <button class="ad-top__icon-btn" id="ad-user-btn"><span class="icon icon--line">person</span></button>
  <div class="ad-pop ad-pop--user">
    <div class="ad-pop__user-head">
      <div class="ad-pop__user-name">홍대식 심사관</div>
      <div class="ad-pop__user-meta">의약품심사부 · ID: hong.ds@mfds.go.kr</div>
    </div>
    <div class="ad-pop__list">
      <a class="ad-pop__item"><span class="icon icon--line">badge</span>마이페이지</a>
      <div class="ad-pop__sep"></div>
      <a class="ad-pop__item ad-pop__item--danger"><span class="icon icon--line">logout</span>로그아웃</a>
    </div>
  </div>
</div>

<!-- 알림 새 항목 -->
<div class="ad-noti-item is-new">
  <div class="ad-noti-item__icon ad-noti-item__icon--urgent"><span class="icon">priority_high</span></div>
  <div class="ad-noti-item__body">
    <div class="ad-noti-item__title">처리 마감 임박 (D-1)<span class="new-dot"></span></div>
    <div class="ad-noti-item__desc">트라스투주맙주 · 셀트리온</div>
  </div>
</div>
portal_admin_login

내부 행정포털 로그인 (.adm-*)

portal_admin_login.html 단독 페이지 전용. portal.css의 .login-*과 분리된 .adm-* 네임스페이스. 로고는 카드 외부 상단, 카드 내부에는 단일 폼, 카드 아래 4개 시스템 바로가기 pill (AI심사포털만 활성).

전체 골격
<body class="adm-body">
  <div class="adm-wrap">
    <!-- 카드 외부 상단 로고 -->
    <p class="adm-logo"><img src="common/img/mfds_logo.png" alt="식품의약품안전처" /></p>

    <div class="adm-card">
      <h1 class="adm-card__title">내부 행정포털시스템</h1>
      <p class="adm-card__sub">식품의약품안전처 · 내부 공무원 전용</p>
      <form>
        <div class="adm-field">
          <label for="uid-admin">아이디</label>
          <div class="adm-input-wrap">
            <span class="icon icon--line">badge</span>
            <input id="uid-admin" type="text" placeholder="공무원 ID" />
          </div>
        </div>
        <button class="adm-submit">로그인</button>
      </form>
    </div>

    <!-- 카드 외부 하단 시스템 바로가기 (AI심사포털만 활성) -->
    <div class="adm-divider"><span>연계 시스템 바로가기</span></div>
    <div class="adm-systems">
      <span class="adm-systems__btn" aria-disabled="true">의약품 통합정보시스템</span>
      <a class="adm-systems__btn adm-systems__btn--primary" href="portal_admin_dashboard.html">AI심사포털</a>
    </div>
  </div>
</body>