Item Tile
아이콘·제목·설명으로 항목을 카드 형태로 고르는 타일입니다. 정책 템플릿, 연동 모듈, 보고서 유형 선택에 씁니다.
1. Default
선택하지 않은 기본 타일입니다.
HTML
<button type="button" class="tile"><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="M12 3a12 12 0 0 0 8.5 3a12 12 0 0 1 -8.5 15a12 12 0 0 1 -8.5 -15a12 12 0 0 0 8.5 -3"/></svg></span><b>USB 제어</b><span>저장장치 차단·읽기 전용</span></button>CSS · .tile, .tile-grid, .tag
/* JS Design System v0.6 · .tile, .tile-grid, .tag · 토큰(var(--*))은 assets/style.css :root 참고 */
.tag{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:600;padding:3px 10px;border-radius:var(--radius-full);line-height:1.6;background:var(--bg-panel);color:var(--text-secondary);white-space:nowrap}
.tag::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor;flex:none}
.tag.critical{background:var(--sev-critical-bg);color:var(--sev-critical-text)}
.tag.high{background:var(--sev-high-bg);color:var(--sev-high-text)}
.tag.medium{background:var(--sev-medium-bg);color:var(--sev-medium-text)}
.tag.low{background:var(--sev-low-bg);color:var(--sev-low-text)}
.tag.info{background:var(--sev-info-bg);color:var(--sev-info-text)}
.tag.ok{background:var(--success-subtle);color:var(--success-text)}
.tag.accent{background:var(--accent-subtle);color:var(--accent-text)}
.tag.sm{font-size:12px;padding:1px 8px}
.tag.lg{font-size:12px;padding:5px 12px}
.tag.plain::before{display:none}
.tag.outline{background:transparent;box-shadow:inset 0 0 0 1px currentColor}
.tag.solid.critical{background:var(--sev-critical);color:var(--sev-critical-on)}
.tag.solid.high{background:var(--sev-high);color:var(--sev-high-on)}
.tag.solid.medium{background:var(--sev-medium);color:var(--sev-medium-on)}
.tag.solid.low{background:var(--sev-low);color:var(--sev-low-on)}
.tag.solid.info{background:var(--sev-info);color:var(--sev-info-on)}
.tag.solid.ok{background:var(--success);color:var(--success-on)}
.tag.solid.accent{background:var(--accent);color:var(--accent-on)}
.tile-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:12px;width:100%}
.tile{display:flex;flex-direction:column;gap:8px;padding:16px;background:var(--bg-surface);border:1px solid var(--border-default);border-radius:var(--radius-lg);cursor:pointer;position:relative;text-align:left;font:inherit;color:var(--text-primary);transition:border-color var(--motion-fast),box-shadow var(--motion-fast)}
.tile:hover{border-color:var(--border-strong);box-shadow:var(--shadow-1)}
.tile.on{border-color:var(--accent);box-shadow:inset 0 0 0 1px var(--accent);background:var(--accent-subtle)}
.tile .ico{width:36px;height:36px;border-radius:var(--radius-lg);background:var(--accent-subtle);color:var(--accent-text);display:grid;place-items:center;font-weight:700;font-size:14px}
.tile.on .ico{background:var(--accent);color:var(--accent-on)}
.tile b{font-size:14px}
.tile span{font-size:12px;color:var(--text-tertiary)}
.tile .tag{position:absolute;top:12px;right:12px}
.tile.horizontal{flex-direction:row;align-items:center}
.tile.horizontal>div{display:flex;flex-direction:column;gap:2px;min-width:0}
.tile[disabled]{opacity:.4;cursor:not-allowed;pointer-events:none}React · @jiran/ds-react
import { Tile } from "@jiran/ds-react";
export default function Example() {
return <Tile icon="shield" title="USB 제어" desc="저장장치 차단·읽기 전용" />;
}2. Grid
button.tile 그리드. 선택은 .on + aria-pressed.
HTML
<div class="tile-grid" style="max-width:760px">
<button type="button" class="tile on" aria-pressed="true"><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="M12 3a12 12 0 0 0 8.5 3a12 12 0 0 1 -8.5 15a12 12 0 0 1 -8.5 -15a12 12 0 0 0 8.5 -3"/></svg></span><b>USB 제어</b><span>저장장치 차단·읽기 전용</span></button>
<button type="button" class="tile" aria-pressed="false"><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 7a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v2a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3v-2"/><path d="M3 15a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v2a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3l0 -2"/><path d="M7 8l0 .01"/><path d="M7 16l0 .01"/></svg></span><b>네트워크 격리</b><span>감염 의심 단말 격리</span></button>
<button type="button" class="tile" aria-pressed="false"><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="M9 6l11 0"/><path d="M9 12l11 0"/><path d="M9 18l11 0"/><path d="M5 6l0 .01"/><path d="M5 12l0 .01"/><path d="M5 18l0 .01"/></svg></span><b>스크립트 제한</b><span>PowerShell·WSH 실행 제어</span></button>
<button type="button" class="tile" aria-pressed="false" disabled><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 13a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v6a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -6"/><path d="M15 9a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v10a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -10"/><path d="M9 5a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v14a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -14"/><path d="M4 20h14"/></svg></span><b>SIEM 연동</b><span>Enterprise 전용</span></button>
</div>CSS · .tile, .tile-grid, .tag
/* JS Design System v0.6 · .tile, .tile-grid, .tag · 토큰(var(--*))은 assets/style.css :root 참고 */
.tag{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:600;padding:3px 10px;border-radius:var(--radius-full);line-height:1.6;background:var(--bg-panel);color:var(--text-secondary);white-space:nowrap}
.tag::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor;flex:none}
.tag.critical{background:var(--sev-critical-bg);color:var(--sev-critical-text)}
.tag.high{background:var(--sev-high-bg);color:var(--sev-high-text)}
.tag.medium{background:var(--sev-medium-bg);color:var(--sev-medium-text)}
.tag.low{background:var(--sev-low-bg);color:var(--sev-low-text)}
.tag.info{background:var(--sev-info-bg);color:var(--sev-info-text)}
.tag.ok{background:var(--success-subtle);color:var(--success-text)}
.tag.accent{background:var(--accent-subtle);color:var(--accent-text)}
.tag.sm{font-size:12px;padding:1px 8px}
.tag.lg{font-size:12px;padding:5px 12px}
.tag.plain::before{display:none}
.tag.outline{background:transparent;box-shadow:inset 0 0 0 1px currentColor}
.tag.solid.critical{background:var(--sev-critical);color:var(--sev-critical-on)}
.tag.solid.high{background:var(--sev-high);color:var(--sev-high-on)}
.tag.solid.medium{background:var(--sev-medium);color:var(--sev-medium-on)}
.tag.solid.low{background:var(--sev-low);color:var(--sev-low-on)}
.tag.solid.info{background:var(--sev-info);color:var(--sev-info-on)}
.tag.solid.ok{background:var(--success);color:var(--success-on)}
.tag.solid.accent{background:var(--accent);color:var(--accent-on)}
.tile-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:12px;width:100%}
.tile{display:flex;flex-direction:column;gap:8px;padding:16px;background:var(--bg-surface);border:1px solid var(--border-default);border-radius:var(--radius-lg);cursor:pointer;position:relative;text-align:left;font:inherit;color:var(--text-primary);transition:border-color var(--motion-fast),box-shadow var(--motion-fast)}
.tile:hover{border-color:var(--border-strong);box-shadow:var(--shadow-1)}
.tile.on{border-color:var(--accent);box-shadow:inset 0 0 0 1px var(--accent);background:var(--accent-subtle)}
.tile .ico{width:36px;height:36px;border-radius:var(--radius-lg);background:var(--accent-subtle);color:var(--accent-text);display:grid;place-items:center;font-weight:700;font-size:14px}
.tile.on .ico{background:var(--accent);color:var(--accent-on)}
.tile b{font-size:14px}
.tile span{font-size:12px;color:var(--text-tertiary)}
.tile .tag{position:absolute;top:12px;right:12px}
.tile.horizontal{flex-direction:row;align-items:center}
.tile.horizontal>div{display:flex;flex-direction:column;gap:2px;min-width:0}
.tile[disabled]{opacity:.4;cursor:not-allowed;pointer-events:none}React · @jiran/ds-react
import { useState } from "react";
import { Tile, TileGrid } from "@jiran/ds-react";
export default function Example() {
const [sel, setSel] = useState("usb");
const pick = (k: string) => ({ selected: sel === k, onSelectedChange: () => setSel(k) });
return (
<TileGrid style={{ maxWidth: 760 }}>
<Tile icon="shield" title="USB 제어" desc="저장장치 차단·읽기 전용" {...pick("usb")} />
<Tile icon="server" title="네트워크 격리" desc="감염 의심 단말 격리" {...pick("net")} />
<Tile icon="list" title="스크립트 제한" desc="PowerShell·WSH 실행 제어" {...pick("script")} />
<Tile icon="chart-bar" title="SIEM 연동" desc="Enterprise 전용" {...pick("siem")} disabled />
</TileGrid>
);
}3. With Tag
우상단에 상태·신규 태그.
HTML
<div class="tile-grid" style="max-width:560px">
<button type="button" class="tile"><span class="tag accent sm plain">NEW</span><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="M10 5a2 2 0 1 1 4 0a7 7 0 0 1 4 6v3a4 4 0 0 0 2 3h-16a4 4 0 0 0 2 -3v-3a7 7 0 0 1 4 -6"/><path d="M9 17v1a3 3 0 0 0 6 0v-1"/></svg></span><b>Slack 알림</b><span>채널로 이벤트 전송</span></button>
<button type="button" class="tile"><span class="tag ok sm">연결됨</span><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="M8 7a4 4 0 1 0 8 0a4 4 0 0 0 -8 0"/><path d="M6 21v-2a4 4 0 0 1 4 -4h4a4 4 0 0 1 4 4v2"/></svg></span><b>AD 연동</b><span>사용자·그룹 동기화</span></button>
</div>CSS · .tile, .tile-grid, .tag
/* JS Design System v0.6 · .tile, .tile-grid, .tag · 토큰(var(--*))은 assets/style.css :root 참고 */
.tag{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:600;padding:3px 10px;border-radius:var(--radius-full);line-height:1.6;background:var(--bg-panel);color:var(--text-secondary);white-space:nowrap}
.tag::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor;flex:none}
.tag.critical{background:var(--sev-critical-bg);color:var(--sev-critical-text)}
.tag.high{background:var(--sev-high-bg);color:var(--sev-high-text)}
.tag.medium{background:var(--sev-medium-bg);color:var(--sev-medium-text)}
.tag.low{background:var(--sev-low-bg);color:var(--sev-low-text)}
.tag.info{background:var(--sev-info-bg);color:var(--sev-info-text)}
.tag.ok{background:var(--success-subtle);color:var(--success-text)}
.tag.accent{background:var(--accent-subtle);color:var(--accent-text)}
.tag.sm{font-size:12px;padding:1px 8px}
.tag.lg{font-size:12px;padding:5px 12px}
.tag.plain::before{display:none}
.tag.outline{background:transparent;box-shadow:inset 0 0 0 1px currentColor}
.tag.solid.critical{background:var(--sev-critical);color:var(--sev-critical-on)}
.tag.solid.high{background:var(--sev-high);color:var(--sev-high-on)}
.tag.solid.medium{background:var(--sev-medium);color:var(--sev-medium-on)}
.tag.solid.low{background:var(--sev-low);color:var(--sev-low-on)}
.tag.solid.info{background:var(--sev-info);color:var(--sev-info-on)}
.tag.solid.ok{background:var(--success);color:var(--success-on)}
.tag.solid.accent{background:var(--accent);color:var(--accent-on)}
.tile-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:12px;width:100%}
.tile{display:flex;flex-direction:column;gap:8px;padding:16px;background:var(--bg-surface);border:1px solid var(--border-default);border-radius:var(--radius-lg);cursor:pointer;position:relative;text-align:left;font:inherit;color:var(--text-primary);transition:border-color var(--motion-fast),box-shadow var(--motion-fast)}
.tile:hover{border-color:var(--border-strong);box-shadow:var(--shadow-1)}
.tile.on{border-color:var(--accent);box-shadow:inset 0 0 0 1px var(--accent);background:var(--accent-subtle)}
.tile .ico{width:36px;height:36px;border-radius:var(--radius-lg);background:var(--accent-subtle);color:var(--accent-text);display:grid;place-items:center;font-weight:700;font-size:14px}
.tile.on .ico{background:var(--accent);color:var(--accent-on)}
.tile b{font-size:14px}
.tile span{font-size:12px;color:var(--text-tertiary)}
.tile .tag{position:absolute;top:12px;right:12px}
.tile.horizontal{flex-direction:row;align-items:center}
.tile.horizontal>div{display:flex;flex-direction:column;gap:2px;min-width:0}
.tile[disabled]{opacity:.4;cursor:not-allowed;pointer-events:none}React · @jiran/ds-react
import { Tag, Tile, TileGrid } from "@jiran/ds-react";
export default function Example() {
return (
<TileGrid style={{ maxWidth: 560 }}>
<Tile icon="bell" title="Slack 알림" desc="채널로 이벤트 전송" tag={<Tag tone="accent" size="sm" variant="plain">NEW</Tag>} />
<Tile icon="user" title="AD 연동" desc="사용자·그룹 동기화" tag={<Tag tone="ok" size="sm">연결됨</Tag>} />
</TileGrid>
);
}4. Horizontal
좁은 폭에서는 가로 배치.
HTML
<div style="display:flex;flex-direction:column;gap:8px;width:100%;max-width:420px">
<button type="button" class="tile horizontal on" aria-pressed="true"><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 13a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v6a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -6"/><path d="M15 9a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v10a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -10"/><path d="M9 5a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v14a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -14"/><path d="M4 20h14"/></svg></span><div><b>주간 요약</b><span>매주 월요일 발송</span></div></button>
<button type="button" class="tile horizontal" aria-pressed="false"><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="M9 6l11 0"/><path d="M9 12l11 0"/><path d="M9 18l11 0"/><path d="M5 6l0 .01"/><path d="M5 12l0 .01"/><path d="M5 18l0 .01"/></svg></span><div><b>상세 이벤트</b><span>CSV · 최대 10만 행</span></div></button>
</div>CSS · .tile, .tile-grid, .tag
/* JS Design System v0.6 · .tile, .tile-grid, .tag · 토큰(var(--*))은 assets/style.css :root 참고 */
.tag{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:600;padding:3px 10px;border-radius:var(--radius-full);line-height:1.6;background:var(--bg-panel);color:var(--text-secondary);white-space:nowrap}
.tag::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor;flex:none}
.tag.critical{background:var(--sev-critical-bg);color:var(--sev-critical-text)}
.tag.high{background:var(--sev-high-bg);color:var(--sev-high-text)}
.tag.medium{background:var(--sev-medium-bg);color:var(--sev-medium-text)}
.tag.low{background:var(--sev-low-bg);color:var(--sev-low-text)}
.tag.info{background:var(--sev-info-bg);color:var(--sev-info-text)}
.tag.ok{background:var(--success-subtle);color:var(--success-text)}
.tag.accent{background:var(--accent-subtle);color:var(--accent-text)}
.tag.sm{font-size:12px;padding:1px 8px}
.tag.lg{font-size:12px;padding:5px 12px}
.tag.plain::before{display:none}
.tag.outline{background:transparent;box-shadow:inset 0 0 0 1px currentColor}
.tag.solid.critical{background:var(--sev-critical);color:var(--sev-critical-on)}
.tag.solid.high{background:var(--sev-high);color:var(--sev-high-on)}
.tag.solid.medium{background:var(--sev-medium);color:var(--sev-medium-on)}
.tag.solid.low{background:var(--sev-low);color:var(--sev-low-on)}
.tag.solid.info{background:var(--sev-info);color:var(--sev-info-on)}
.tag.solid.ok{background:var(--success);color:var(--success-on)}
.tag.solid.accent{background:var(--accent);color:var(--accent-on)}
.tile-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:12px;width:100%}
.tile{display:flex;flex-direction:column;gap:8px;padding:16px;background:var(--bg-surface);border:1px solid var(--border-default);border-radius:var(--radius-lg);cursor:pointer;position:relative;text-align:left;font:inherit;color:var(--text-primary);transition:border-color var(--motion-fast),box-shadow var(--motion-fast)}
.tile:hover{border-color:var(--border-strong);box-shadow:var(--shadow-1)}
.tile.on{border-color:var(--accent);box-shadow:inset 0 0 0 1px var(--accent);background:var(--accent-subtle)}
.tile .ico{width:36px;height:36px;border-radius:var(--radius-lg);background:var(--accent-subtle);color:var(--accent-text);display:grid;place-items:center;font-weight:700;font-size:14px}
.tile.on .ico{background:var(--accent);color:var(--accent-on)}
.tile b{font-size:14px}
.tile span{font-size:12px;color:var(--text-tertiary)}
.tile .tag{position:absolute;top:12px;right:12px}
.tile.horizontal{flex-direction:row;align-items:center}
.tile.horizontal>div{display:flex;flex-direction:column;gap:2px;min-width:0}
.tile[disabled]{opacity:.4;cursor:not-allowed;pointer-events:none}React · @jiran/ds-react
import { useState } from "react";
import { Tile } from "@jiran/ds-react";
export default function Example() {
const [sel, setSel] = useState("weekly");
return (
<div style={{ display: "flex", flexDirection: "column", gap: 8, width: "100%", maxWidth: 420 }}>
<Tile horizontal icon="chart-bar" title="주간 요약" desc="매주 월요일 발송" selected={sel === "weekly"} onSelectedChange={() => setSel("weekly")} />
<Tile horizontal icon="list" title="상세 이벤트" desc="CSV · 최대 10만 행" selected={sel === "detail"} onSelectedChange={() => setSel("detail")} />
</div>
);
}Props
HTML 에서는 클래스와 속성으로, React(@jiran/ds-react)에서는 같은 이름의 prop(variant · size …)으로 변형·상태를 지정합니다.
| Prop / Class | Type · Values | Default | Description |
|---|---|---|---|
| .tile | button | — | .ico + b(제목) + span(설명). aria-pressed |
| .on | boolean | false | 선택(accent 보더·배경) |
| .horizontal | boolean | false | 가로 배치 |
| disabled | attribute | — | 선택 불가 |
| .tile-grid | container | — | auto-fill 180px 그리드 |
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 { Tile, TileGrid } 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 .tile, .tile-grid, .tag
/* JS Design System v0.6 · .tile, .tile-grid, .tag · 토큰(var(--*))은 assets/style.css :root 참고 */
.tag{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:600;padding:3px 10px;border-radius:var(--radius-full);line-height:1.6;background:var(--bg-panel);color:var(--text-secondary);white-space:nowrap}
.tag::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor;flex:none}
.tag.critical{background:var(--sev-critical-bg);color:var(--sev-critical-text)}
.tag.high{background:var(--sev-high-bg);color:var(--sev-high-text)}
.tag.medium{background:var(--sev-medium-bg);color:var(--sev-medium-text)}
.tag.low{background:var(--sev-low-bg);color:var(--sev-low-text)}
.tag.info{background:var(--sev-info-bg);color:var(--sev-info-text)}
.tag.ok{background:var(--success-subtle);color:var(--success-text)}
.tag.accent{background:var(--accent-subtle);color:var(--accent-text)}
.tag.sm{font-size:12px;padding:1px 8px}
.tag.lg{font-size:12px;padding:5px 12px}
.tag.plain::before{display:none}
.tag.outline{background:transparent;box-shadow:inset 0 0 0 1px currentColor}
.tag.solid.critical{background:var(--sev-critical);color:var(--sev-critical-on)}
.tag.solid.high{background:var(--sev-high);color:var(--sev-high-on)}
.tag.solid.medium{background:var(--sev-medium);color:var(--sev-medium-on)}
.tag.solid.low{background:var(--sev-low);color:var(--sev-low-on)}
.tag.solid.info{background:var(--sev-info);color:var(--sev-info-on)}
.tag.solid.ok{background:var(--success);color:var(--success-on)}
.tag.solid.accent{background:var(--accent);color:var(--accent-on)}
.tile-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:12px;width:100%}
.tile{display:flex;flex-direction:column;gap:8px;padding:16px;background:var(--bg-surface);border:1px solid var(--border-default);border-radius:var(--radius-lg);cursor:pointer;position:relative;text-align:left;font:inherit;color:var(--text-primary);transition:border-color var(--motion-fast),box-shadow var(--motion-fast)}
.tile:hover{border-color:var(--border-strong);box-shadow:var(--shadow-1)}
.tile.on{border-color:var(--accent);box-shadow:inset 0 0 0 1px var(--accent);background:var(--accent-subtle)}
.tile .ico{width:36px;height:36px;border-radius:var(--radius-lg);background:var(--accent-subtle);color:var(--accent-text);display:grid;place-items:center;font-weight:700;font-size:14px}
.tile.on .ico{background:var(--accent);color:var(--accent-on)}
.tile b{font-size:14px}
.tile span{font-size:12px;color:var(--text-tertiary)}
.tile .tag{position:absolute;top:12px;right:12px}
.tile.horizontal{flex-direction:row;align-items:center}
.tile.horizontal>div{display:flex;flex-direction:column;gap:2px;min-width:0}
.tile[disabled]{opacity:.4;cursor:not-allowed;pointer-events:none}