Notification
시스템 상태와 결과를 알립니다. 페이지 안에 머무는 Notice, 잠시 떴다 사라지는 Toast, 화면 상단 전체 공지 Banner 를 구분합니다.
1. Default
본문 안에 머무는 기본 인라인 알림입니다.
정책이 아직 배포되지 않았습니다변경 사항은 '배포'를 눌러야 에이전트에 적용됩니다.
HTML
<div class="notice info" role="status" style="max-width:600px"><span class="ico"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0"/><path d="M12 9h.01"/><path d="M11 12h1v4h1"/></svg></span><div><b>정책이 아직 배포되지 않았습니다</b>변경 사항은 '배포'를 눌러야 에이전트에 적용됩니다.</div></div>CSS · .notice, .toast, .toast-stack, .banner
/* JS Design System v0.6 · .notice, .toast, .toast-stack, .banner · 토큰(var(--*))은 assets/style.css :root 참고 */
.notice{display:flex;gap:12px;align-items:flex-start;border-radius:var(--radius-lg);padding:14px 18px;font-size:14px;border:1px solid var(--border-default);width:100%;background:var(--bg-surface);line-height:1.55}
.notice b{display:block;margin-bottom:2px}
.notice .ico{flex:none;width:20px;height:20px;display:grid;place-items:center;color:var(--info-text);margin-top:1px}
.notice .ico svg{width:20px;height:20px}
.notice .close{margin-left:auto;flex:none;border:0;background:transparent;color:var(--text-tertiary);font:inherit;line-height:1;cursor:pointer;padding:2px;display:grid;place-items:center}
.notice .close svg{width:14px;height:14px}
.notice .close:hover{color:var(--text-primary)}
.notice .actions{display:flex;gap:8px;margin-top:8px}
.notice.info{background:var(--info-subtle);border-color:color-mix(in srgb,var(--info) 30%,transparent)}
.notice.success{background:var(--success-subtle);border-color:color-mix(in srgb,var(--success) 30%,transparent)}
.notice.success .ico{color:var(--success-text)}
.notice.warning{background:var(--warning-subtle);border-color:color-mix(in srgb,var(--warning) 30%,transparent)}
.notice.warning .ico{color:var(--warning-text)}
.notice.danger{background:var(--danger-subtle);border-color:color-mix(in srgb,var(--danger) 30%,transparent)}
.notice.danger .ico{color:var(--danger-text)}
.toast{display:inline-flex;align-items:center;gap:12px;width:360px;max-width:100%;padding:12px 16px;border-radius:var(--radius-lg);background:var(--bg-inverse);color:var(--text-inverse);font-size:14px;box-shadow:var(--shadow-3)}
.toast .ico{flex:none;width:20px;height:20px;display:grid;place-items:center;color:var(--success)}
.toast .ico svg{width:20px;height:20px}
.toast.danger .ico{color:var(--danger)}
.toast .action{margin-left:auto;background:none;border:0;color:var(--accent-inverse);font:inherit;font-size:12px;font-weight:600;cursor:pointer;white-space:nowrap}
.toast .action:hover{text-decoration:underline}
.toast-stack{display:flex;flex-direction:column;gap:8px;align-items:flex-end}
.toast-stack.fixed{position:fixed;right:24px;bottom:24px;z-index:110}
.banner{display:flex;align-items:center;gap:12px;width:100%;padding:10px 20px;background:var(--accent);color:var(--accent-on);font-size:14px;font-weight:500}
.banner .btn{margin-left:auto}
.banner.warning{background:var(--warning);color:var(--warning-on)}
.banner.danger{background:var(--danger);color:var(--danger-on)}React · @jiran/ds-react
import { Notice } from "@jiran/ds-react";
export default function Example() {
return (
<Notice tone="info" title="정책이 아직 배포되지 않았습니다" style={{ maxWidth: 600 }}>
변경 사항은 '배포'를 눌러야 에이전트에 적용됩니다.
</Notice>
);
}2. Notice (Inline)
페이지에 고정. Info · Success · Warning · Danger. role=status(정보) 또는 alert(위험).
정책이 아직 배포되지 않았습니다변경 사항은 '배포'를 눌러야 에이전트에 적용됩니다.
배포 완료1,284대 중 1,284대에 적용되었습니다.
라이선스가 3일 후 만료됩니다만료 시 신규 이벤트 수집이 중단됩니다.
에이전트 37대 연결 끊김10분 이상 체크인이 없습니다. 네트워크 상태를 확인하세요.
HTML
<div class="notice info" role="status" style="max-width:600px"><span class="ico"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0"/><path d="M12 9h.01"/><path d="M11 12h1v4h1"/></svg></span><div><b>정책이 아직 배포되지 않았습니다</b>변경 사항은 '배포'를 눌러야 에이전트에 적용됩니다.</div><button type="button" class="close" aria-label="닫기"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6l-12 12"/><path d="M6 6l12 12"/></svg></button></div>
<div class="notice success" role="status" style="max-width:600px"><span class="ico"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"/><path d="M9 12l2 2l4 -4"/></svg></span><div><b>배포 완료</b>1,284대 중 1,284대에 적용되었습니다.</div></div>
<div class="notice warning" role="status" style="max-width:600px"><span class="ico"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 9v4"/><path d="M10.363 3.591l-8.106 13.534a1.914 1.914 0 0 0 1.636 2.871h16.214a1.914 1.914 0 0 0 1.636 -2.87l-8.106 -13.536a1.914 1.914 0 0 0 -3.274 0"/><path d="M12 16h.01"/></svg></span><div><b>라이선스가 3일 후 만료됩니다</b>만료 시 신규 이벤트 수집이 중단됩니다.<div class="actions"><button type="button" class="btn sm primary">갱신 요청</button></div></div></div>
<div class="notice danger" role="alert" style="max-width:600px"><span class="ico"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0"/><path d="M12 8v4"/><path d="M12 16h.01"/></svg></span><div><b>에이전트 37대 연결 끊김</b>10분 이상 체크인이 없습니다. 네트워크 상태를 확인하세요.</div></div>CSS · .notice, .toast, .toast-stack, .banner
/* JS Design System v0.6 · .notice, .toast, .toast-stack, .banner · 토큰(var(--*))은 assets/style.css :root 참고 */
.notice{display:flex;gap:12px;align-items:flex-start;border-radius:var(--radius-lg);padding:14px 18px;font-size:14px;border:1px solid var(--border-default);width:100%;background:var(--bg-surface);line-height:1.55}
.notice b{display:block;margin-bottom:2px}
.notice .ico{flex:none;width:20px;height:20px;display:grid;place-items:center;color:var(--info-text);margin-top:1px}
.notice .ico svg{width:20px;height:20px}
.notice .close{margin-left:auto;flex:none;border:0;background:transparent;color:var(--text-tertiary);font:inherit;line-height:1;cursor:pointer;padding:2px;display:grid;place-items:center}
.notice .close svg{width:14px;height:14px}
.notice .close:hover{color:var(--text-primary)}
.notice .actions{display:flex;gap:8px;margin-top:8px}
.notice.info{background:var(--info-subtle);border-color:color-mix(in srgb,var(--info) 30%,transparent)}
.notice.success{background:var(--success-subtle);border-color:color-mix(in srgb,var(--success) 30%,transparent)}
.notice.success .ico{color:var(--success-text)}
.notice.warning{background:var(--warning-subtle);border-color:color-mix(in srgb,var(--warning) 30%,transparent)}
.notice.warning .ico{color:var(--warning-text)}
.notice.danger{background:var(--danger-subtle);border-color:color-mix(in srgb,var(--danger) 30%,transparent)}
.notice.danger .ico{color:var(--danger-text)}
.toast{display:inline-flex;align-items:center;gap:12px;width:360px;max-width:100%;padding:12px 16px;border-radius:var(--radius-lg);background:var(--bg-inverse);color:var(--text-inverse);font-size:14px;box-shadow:var(--shadow-3)}
.toast .ico{flex:none;width:20px;height:20px;display:grid;place-items:center;color:var(--success)}
.toast .ico svg{width:20px;height:20px}
.toast.danger .ico{color:var(--danger)}
.toast .action{margin-left:auto;background:none;border:0;color:var(--accent-inverse);font:inherit;font-size:12px;font-weight:600;cursor:pointer;white-space:nowrap}
.toast .action:hover{text-decoration:underline}
.toast-stack{display:flex;flex-direction:column;gap:8px;align-items:flex-end}
.toast-stack.fixed{position:fixed;right:24px;bottom:24px;z-index:110}
.banner{display:flex;align-items:center;gap:12px;width:100%;padding:10px 20px;background:var(--accent);color:var(--accent-on);font-size:14px;font-weight:500}
.banner .btn{margin-left:auto}
.banner.warning{background:var(--warning);color:var(--warning-on)}
.banner.danger{background:var(--danger);color:var(--danger-on)}React · @jiran/ds-react
import { Button, Notice } from "@jiran/ds-react";
export default function Example() {
return (
<>
<Notice tone="info" title="정책이 아직 배포되지 않았습니다" onClose={() => {}} style={{ maxWidth: 600 }}>
변경 사항은 '배포'를 눌러야 에이전트에 적용됩니다.
</Notice>
<Notice tone="success" title="배포 완료" style={{ maxWidth: 600 }}>
1,284대 중 1,284대에 적용되었습니다.
</Notice>
<Notice tone="warning" title="라이선스가 3일 후 만료됩니다" actions={<Button size="sm">갱신 요청</Button>} style={{ maxWidth: 600 }}>
만료 시 신규 이벤트 수집이 중단됩니다.
</Notice>
<Notice tone="danger" title="에이전트 37대 연결 끊김" style={{ maxWidth: 600 }}>
10분 이상 체크인이 없습니다. 네트워크 상태를 확인하세요.
</Notice>
</>
);
}3. Toast
짧은 결과 알림. 우측 하단, 3~5초 후 자동 소멸, 실행 취소 액션 가능. aria-live=polite.
정책 'USB 차단' 이 저장되었습니다
내보내기에 실패했습니다
HTML
<div class="toast-stack" aria-live="polite">
<div class="toast"><span class="ico"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"/><path d="M9 12l2 2l4 -4"/></svg></span>정책 'USB 차단' 이 저장되었습니다<button type="button" class="action">실행 취소</button></div>
<div class="toast danger"><span class="ico"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0"/><path d="M12 8v4"/><path d="M12 16h.01"/></svg></span>내보내기에 실패했습니다<button type="button" class="action">다시 시도</button></div>
</div>CSS · .notice, .toast, .toast-stack, .banner
/* JS Design System v0.6 · .notice, .toast, .toast-stack, .banner · 토큰(var(--*))은 assets/style.css :root 참고 */
.notice{display:flex;gap:12px;align-items:flex-start;border-radius:var(--radius-lg);padding:14px 18px;font-size:14px;border:1px solid var(--border-default);width:100%;background:var(--bg-surface);line-height:1.55}
.notice b{display:block;margin-bottom:2px}
.notice .ico{flex:none;width:20px;height:20px;display:grid;place-items:center;color:var(--info-text);margin-top:1px}
.notice .ico svg{width:20px;height:20px}
.notice .close{margin-left:auto;flex:none;border:0;background:transparent;color:var(--text-tertiary);font:inherit;line-height:1;cursor:pointer;padding:2px;display:grid;place-items:center}
.notice .close svg{width:14px;height:14px}
.notice .close:hover{color:var(--text-primary)}
.notice .actions{display:flex;gap:8px;margin-top:8px}
.notice.info{background:var(--info-subtle);border-color:color-mix(in srgb,var(--info) 30%,transparent)}
.notice.success{background:var(--success-subtle);border-color:color-mix(in srgb,var(--success) 30%,transparent)}
.notice.success .ico{color:var(--success-text)}
.notice.warning{background:var(--warning-subtle);border-color:color-mix(in srgb,var(--warning) 30%,transparent)}
.notice.warning .ico{color:var(--warning-text)}
.notice.danger{background:var(--danger-subtle);border-color:color-mix(in srgb,var(--danger) 30%,transparent)}
.notice.danger .ico{color:var(--danger-text)}
.toast{display:inline-flex;align-items:center;gap:12px;width:360px;max-width:100%;padding:12px 16px;border-radius:var(--radius-lg);background:var(--bg-inverse);color:var(--text-inverse);font-size:14px;box-shadow:var(--shadow-3)}
.toast .ico{flex:none;width:20px;height:20px;display:grid;place-items:center;color:var(--success)}
.toast .ico svg{width:20px;height:20px}
.toast.danger .ico{color:var(--danger)}
.toast .action{margin-left:auto;background:none;border:0;color:var(--accent-inverse);font:inherit;font-size:12px;font-weight:600;cursor:pointer;white-space:nowrap}
.toast .action:hover{text-decoration:underline}
.toast-stack{display:flex;flex-direction:column;gap:8px;align-items:flex-end}
.toast-stack.fixed{position:fixed;right:24px;bottom:24px;z-index:110}
.banner{display:flex;align-items:center;gap:12px;width:100%;padding:10px 20px;background:var(--accent);color:var(--accent-on);font-size:14px;font-weight:500}
.banner .btn{margin-left:auto}
.banner.warning{background:var(--warning);color:var(--warning-on)}
.banner.danger{background:var(--danger);color:var(--danger-on)}React · @jiran/ds-react
import { Button, ButtonGroup, ToastProvider, useToast } from "@jiran/ds-react";
function Demo() {
const toast = useToast();
return (
<ButtonGroup>
<Button onClick={() => toast.show({ message: "정책 'USB 차단' 이 저장되었습니다", action: { label: "실행 취소", onClick: () => {} } })}>저장</Button>
<Button variant="danger-secondary" onClick={() => toast.show({ tone: "danger", message: "내보내기에 실패했습니다", action: { label: "다시 시도", onClick: () => {} } })}>
실패 알림
</Button>
</ButtonGroup>
);
}
/** 앱 루트에 ToastProvider 를 한 번 두고, 어디서든 useToast().show(...) */
export default function Example() {
return (
<ToastProvider duration={4000} max={3}>
<Demo />
</ToastProvider>
);
}4. Banner
시스템 전체 공지(점검·라이선스). 헤더 위 전체 폭, 닫기 가능.
HTML
<div class="banner" role="status"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0"/><path d="M12 9h.01"/><path d="M11 12h1v4h1"/></svg>9월 10일 02:00~04:00 정기 점검이 예정되어 있습니다. 점검 중 콘솔 접속이 제한됩니다.<button type="button" class="btn sm secondary">자세히</button></div>CSS · .notice, .toast, .toast-stack, .banner
/* JS Design System v0.6 · .notice, .toast, .toast-stack, .banner · 토큰(var(--*))은 assets/style.css :root 참고 */
.notice{display:flex;gap:12px;align-items:flex-start;border-radius:var(--radius-lg);padding:14px 18px;font-size:14px;border:1px solid var(--border-default);width:100%;background:var(--bg-surface);line-height:1.55}
.notice b{display:block;margin-bottom:2px}
.notice .ico{flex:none;width:20px;height:20px;display:grid;place-items:center;color:var(--info-text);margin-top:1px}
.notice .ico svg{width:20px;height:20px}
.notice .close{margin-left:auto;flex:none;border:0;background:transparent;color:var(--text-tertiary);font:inherit;line-height:1;cursor:pointer;padding:2px;display:grid;place-items:center}
.notice .close svg{width:14px;height:14px}
.notice .close:hover{color:var(--text-primary)}
.notice .actions{display:flex;gap:8px;margin-top:8px}
.notice.info{background:var(--info-subtle);border-color:color-mix(in srgb,var(--info) 30%,transparent)}
.notice.success{background:var(--success-subtle);border-color:color-mix(in srgb,var(--success) 30%,transparent)}
.notice.success .ico{color:var(--success-text)}
.notice.warning{background:var(--warning-subtle);border-color:color-mix(in srgb,var(--warning) 30%,transparent)}
.notice.warning .ico{color:var(--warning-text)}
.notice.danger{background:var(--danger-subtle);border-color:color-mix(in srgb,var(--danger) 30%,transparent)}
.notice.danger .ico{color:var(--danger-text)}
.toast{display:inline-flex;align-items:center;gap:12px;width:360px;max-width:100%;padding:12px 16px;border-radius:var(--radius-lg);background:var(--bg-inverse);color:var(--text-inverse);font-size:14px;box-shadow:var(--shadow-3)}
.toast .ico{flex:none;width:20px;height:20px;display:grid;place-items:center;color:var(--success)}
.toast .ico svg{width:20px;height:20px}
.toast.danger .ico{color:var(--danger)}
.toast .action{margin-left:auto;background:none;border:0;color:var(--accent-inverse);font:inherit;font-size:12px;font-weight:600;cursor:pointer;white-space:nowrap}
.toast .action:hover{text-decoration:underline}
.toast-stack{display:flex;flex-direction:column;gap:8px;align-items:flex-end}
.toast-stack.fixed{position:fixed;right:24px;bottom:24px;z-index:110}
.banner{display:flex;align-items:center;gap:12px;width:100%;padding:10px 20px;background:var(--accent);color:var(--accent-on);font-size:14px;font-weight:500}
.banner .btn{margin-left:auto}
.banner.warning{background:var(--warning);color:var(--warning-on)}
.banner.danger{background:var(--danger);color:var(--danger-on)}React · @jiran/ds-react
import { Banner, Button } from "@jiran/ds-react";
export default function Example() {
return (
<Banner action={<Button size="sm" variant="secondary">자세히</Button>}>
9월 10일 02:00~04:00 정기 점검이 예정되어 있습니다. 점검 중 콘솔 접속이 제한됩니다.
</Banner>
);
}Props
HTML 에서는 클래스와 속성으로, React(@jiran/ds-react)에서는 같은 이름의 prop(variant · size …)으로 변형·상태를 지정합니다.
| Prop / Class | Type · Values | Default | Description |
|---|---|---|---|
| .notice | div | — | role=status | alert. .ico + div(b 제목 + 본문 + .actions) + .close |
| tone | info | success | warning | danger | neutral | 톤별 subtle 배경 + 30% 보더 |
| .toast | div | — | 폭 360, 어두운 배경. .action 하나 |
| .toast-stack | container | — | aria-live=polite, 우측 하단 고정 |
| .banner | div | — | 전체 폭. accent / .warning / .danger |
Usage
React: @jiran/ds-react 패키지를 설치하고 style.css 를 한 번 import 하면 위 React 탭 코드를 그대로 쓸 수 있습니다(React Package). HTML: assets/style.css 를 연결하고(일부만 필요하면 아래 컴포넌트 CSS 복사), 동작이 필요하면 assets/ds.js 를 함께 넣습니다 — 이 페이지의 프리뷰가 그 스크립트로 동작합니다. 색은 전부 토큰(var(--accent) 등)을 참조하므로 --accent-* 만 제품 컬러로 바꾸면 됩니다.
React @jiran/ds-react
npm i @jiran/ds-react
// main.tsx — 앱 진입점에서 한 번
import "@jiran/ds-react/style.css";
// 컴포넌트
import { Notice, Toast, ToastStack, Banner, ToastProvider, useToast } from "@jiran/ds-react";HTML
<!-- 1) 토큰 + 전체 컴포넌트 스타일 한 번에 연결 -->
<link rel="stylesheet" href="assets/style.css">
<!-- 동작(드롭다운·탭·달력·표 정렬/선택·토스트 등) — 순수 JS 한 파일. React 제품은 불필요 -->
<script src="assets/ds.js" defer></script>
<!-- 2) 또는 아래 "Component CSS" 만 프로젝트 CSS 에 붙이고,
:root 토큰은 Foundations › Design Token 에서 복사 -->Component CSS .notice, .toast, .toast-stack, .banner
/* JS Design System v0.6 · .notice, .toast, .toast-stack, .banner · 토큰(var(--*))은 assets/style.css :root 참고 */
.notice{display:flex;gap:12px;align-items:flex-start;border-radius:var(--radius-lg);padding:14px 18px;font-size:14px;border:1px solid var(--border-default);width:100%;background:var(--bg-surface);line-height:1.55}
.notice b{display:block;margin-bottom:2px}
.notice .ico{flex:none;width:20px;height:20px;display:grid;place-items:center;color:var(--info-text);margin-top:1px}
.notice .ico svg{width:20px;height:20px}
.notice .close{margin-left:auto;flex:none;border:0;background:transparent;color:var(--text-tertiary);font:inherit;line-height:1;cursor:pointer;padding:2px;display:grid;place-items:center}
.notice .close svg{width:14px;height:14px}
.notice .close:hover{color:var(--text-primary)}
.notice .actions{display:flex;gap:8px;margin-top:8px}
.notice.info{background:var(--info-subtle);border-color:color-mix(in srgb,var(--info) 30%,transparent)}
.notice.success{background:var(--success-subtle);border-color:color-mix(in srgb,var(--success) 30%,transparent)}
.notice.success .ico{color:var(--success-text)}
.notice.warning{background:var(--warning-subtle);border-color:color-mix(in srgb,var(--warning) 30%,transparent)}
.notice.warning .ico{color:var(--warning-text)}
.notice.danger{background:var(--danger-subtle);border-color:color-mix(in srgb,var(--danger) 30%,transparent)}
.notice.danger .ico{color:var(--danger-text)}
.toast{display:inline-flex;align-items:center;gap:12px;width:360px;max-width:100%;padding:12px 16px;border-radius:var(--radius-lg);background:var(--bg-inverse);color:var(--text-inverse);font-size:14px;box-shadow:var(--shadow-3)}
.toast .ico{flex:none;width:20px;height:20px;display:grid;place-items:center;color:var(--success)}
.toast .ico svg{width:20px;height:20px}
.toast.danger .ico{color:var(--danger)}
.toast .action{margin-left:auto;background:none;border:0;color:var(--accent-inverse);font:inherit;font-size:12px;font-weight:600;cursor:pointer;white-space:nowrap}
.toast .action:hover{text-decoration:underline}
.toast-stack{display:flex;flex-direction:column;gap:8px;align-items:flex-end}
.toast-stack.fixed{position:fixed;right:24px;bottom:24px;z-index:110}
.banner{display:flex;align-items:center;gap:12px;width:100%;padding:10px 20px;background:var(--accent);color:var(--accent-on);font-size:14px;font-weight:500}
.banner .btn{margin-left:auto}
.banner.warning{background:var(--warning);color:var(--warning-on)}
.banner.danger{background:var(--danger);color:var(--danger-on)}