コンポーネント
再利用可能なUIコンポーネントのライブラリです。すべてのコンポーネントは、 アクセシビリティ、レスポンシブデザイン、ダークモード対応を考慮して設計されています。
💡 ヒント:各コンポーネントのコードブロック右上の「コピー」ボタンで、コードをクリップボードにコピーできます。
リンク
リンクは使用するコンテキストに応じて2つのスタイルを使い分けます。
ナビゲーション・独立リンク
ナビゲーションメニュー、フッター、CTA的なリンクに使用します。 ホバー時に明確なアンダーラインを表示し、クリック可能であることを視覚的に示します。
<a href="#">通常のリンク</a>
a {
color: var(--color-primary);
text-decoration: none;
transition: color var(--transition-base) ease;
}
a:hover {
text-decoration: underline;
text-underline-offset: 0.25em;
}
本文内リンク(.text-link)
段落内の本文リンクに使用します。通常時は本文に馴染み、 ホバー時にアニメーションで下部ボーダーを表示します。
Misora Design Systemは、 「空気のような接続性」 というコアコンセプトに基づいて設計されています。 詳細は デザインガイドライン を参照してください。
法人顧客向けの IoT/M2M通信サービス および モバイルワーカー向けソリューション を提供しています。
<p>
詳細は<a href="#" class="text-link">デザインガイドライン</a>を参照してください。
</p>
.text-link {
color: var(--color-text-primary);
text-decoration: none;
border-bottom: 1px solid transparent;
transition: border-color var(--transition-base) ease;
}
.text-link:hover {
border-bottom-color: var(--color-primary);
text-decoration: none;
}
使い分けガイドライン
- 通常リンク:ナビゲーション、フッターリンク、スタンドアロンのリンクに使用
- .text-link:本文(<p> 内など)のリンクに使用。本文の可読性を保ちつつ、ホバー時に視覚的フィードバックを提供
フォームフィールド
ユーザー入力を受け付けるフォーム要素です。フォーカス時にはミソラブルーでハイライトされ、 現在入力中のフィールドが明確になります。
テキスト入力
名前、メールアドレス、電話番号などの一行テキスト入力に使用します。
<div class="form-group">
<label for="name">お名前</label>
<input type="text" id="name" placeholder="山田 太郎">
</div>
input[type="text"],
input[type="email"],
input[type="tel"] {
width: 100%;
padding: var(--spacing-md);
font-size: var(--font-size-base);
color: var(--color-text-primary);
background-color: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: 0.375rem;
transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
input:focus {
outline: none;
border-color: var(--color-primary);
box-shadow: 0 0 0 3px rgba(67, 198, 250, 0.1);
}
テキストエリア
問い合わせ内容、メッセージなどの複数行テキスト入力に使用します。
<div class="form-group">
<label for="message">お問い合わせ内容</label>
<textarea id="message" rows="5"></textarea>
</div>
セレクトボックス
複数の選択肢から1つを選択する場合に使用します。
<div class="form-group">
<label for="service">サービス種別</label>
<select id="service">
<option>選択してください</option>
<option>IoT/M2M向けサービス</option>
<option>モバイルワーカー向けサービス</option>
</select>
</div>
日付選択(Datepicker)
カレンダーから日付を選択するためのコンポーネントです。 日本語表記、土日の色分け、今日の日付のハイライトに対応しています。
基本的な日付選択
入力フィールドをクリックするとカレンダーが表示され、日付を選択できます。 選択された日付は「YYYY/MM/DD」形式で入力フィールドに表示されます。
<div class="form-group">
<label for="datepicker">日付を選択</label>
<input type="text" id="datepicker" class="datepicker-input" placeholder="日付を選択してください" readonly>
</div>
// 自動初期化
// クラス名 'datepicker-input' を持つすべての入力フィールドに対して
// 自動的にDatepickerが初期化されます
// または手動で初期化
const input = document.querySelector('#my-datepicker');
const datepicker = new MisoraDesignSystem.Datepicker(input);
主な機能
- カレンダー表示で視覚的に日付を選択
- 月・年の切り替えナビゲーション
- 今日の日付をハイライト表示
- 土曜日・日曜日の色分け
- 選択された日付の強調表示
- ダークモード完全対応
- レスポンシブデザイン
年月選択(Month Picker)
年と月を選択するためのコンポーネントです。 月次レポート、契約期間、統計データなど、月単位で情報を扱う場合に便利です。
基本的な年月選択
入力フィールドをクリックすると12ヶ月のグリッドが表示され、月を選択できます。 年の切り替えもナビゲーションボタンで簡単に行えます。 選択された年月は「YYYY/MM」形式で入力フィールドに表示されます。
<div class="form-group">
<label for="monthpicker">年月を選択</label>
<input type="text" id="monthpicker" class="monthpicker-input" placeholder="年月を選択してください" readonly>
</div>
// 自動初期化
// クラス名 'monthpicker-input' を持つすべての入力フィールドに対して
// 自動的にMonthPickerが初期化されます
// または手動で初期化
const input = document.querySelector('#my-monthpicker');
const monthpicker = new MisoraDesignSystem.MonthPicker(input);
主な機能
- 12ヶ月をグリッド表示で一覧
- 年の切り替えナビゲーション
- 現在の月をハイライト表示
- 選択された月の強調表示
- ダークモード完全対応
- レスポンシブデザイン
モーダル
重要な情報を表示したり、ユーザーの注意を引く必要がある場合に使用します。 背景をオーバーレイし、モーダル外をクリックするか、Escキーで閉じることができます。
基本的なモーダル
確認ダイアログ、詳細情報の表示、フォーム入力などに使用します。
<!-- トリガーボタン -->
<button class="btn btn-primary" data-modal-target="my-modal">
モーダルを開く
</button>
<!-- モーダル -->
<div id="my-modal" class="modal-overlay">
<div class="modal">
<div class="modal-header">
<h3 class="modal-title">モーダルタイトル</h3>
<button class="modal-close">×</button>
</div>
<div class="modal-body">
<p>モーダルのコンテンツがここに入ります。</p>
</div>
<div class="modal-footer">
<button class="btn btn-outline" data-modal-close>
キャンセル
</button>
<button class="btn btn-primary">確認</button>
</div>
</div>
</div>
.modal-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.6);
z-index: 1000;
justify-content: center;
align-items: center;
}
.modal-overlay.active {
display: flex;
}
.modal {
background-color: var(--color-surface);
border-radius: 0.5rem;
box-shadow: var(--shadow-lg);
max-width: 500px;
width: 90%;
}
// モーダルを開く
document.querySelector('[data-modal-target]')
.addEventListener('click', (e) => {
const modalId = e.target.getAttribute('data-modal-target');
document.getElementById(modalId).classList.add('active');
});
// モーダルを閉じる
document.querySelector('.modal-close')
.addEventListener('click', (e) => {
e.target.closest('.modal-overlay').classList.remove('active');
});
サイドパネル
画面の右側または左側からスライドインするパネルコンポーネントです。 設定、詳細情報、ナビゲーションメニューなどに使用します。
右側からのサイドパネル
デフォルトでは右側からスライドインします。設定パネルや詳細情報の表示に適しています。
<!-- トリガーボタン -->
<button data-sidepanel-target="sidepanel-right">パネルを開く</button>
<!-- サイドパネル -->
<div id="sidepanel-right" class="sidepanel-overlay">
<div class="sidepanel sidepanel-right">
<div class="sidepanel-header">
<h3 class="sidepanel-title">設定</h3>
<button class="sidepanel-close">×</button>
</div>
<div class="sidepanel-body">
<!-- コンテンツ -->
</div>
<div class="sidepanel-footer">
<button class="btn btn-primary">保存</button>
</div>
</div>
</div>
左側からのサイドパネル
sidepanel-left クラスを追加すると左側からスライドインします。
ナビゲーションメニューなどに適しています。
<div class="sidepanel sidepanel-left">
<!-- 左側から表示 -->
</div>
JavaScriptで開く
JavaScriptから直接サイドパネルを開くこともできます。
// サイドパネルを開く
function openSidepanel(sidepanelId) {
const overlay = document.getElementById(sidepanelId);
const sidepanel = overlay.querySelector('.sidepanel');
overlay.classList.add('active');
setTimeout(() => {
sidepanel.classList.add('active');
}, 10);
document.body.style.overflow = 'hidden';
}
// サイドパネルを閉じる
function closeSidepanel(sidepanelId) {
const overlay = document.getElementById(sidepanelId);
const sidepanel = overlay.querySelector('.sidepanel');
sidepanel.classList.remove('active');
setTimeout(() => {
overlay.classList.remove('active');
document.body.style.overflow = '';
}, 300);
}
グリッド
レスポンシブなレイアウトを構築するためのグリッドシステムです。 CSS Gridをベースに、モバイルファーストのアプローチで設計されています。
基本的なグリッド
.grid クラスと .grid-cols-* クラスを組み合わせて使用します。
<div class="grid grid-cols-3 gap-md">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
カラム数のバリエーション
1〜6カラムおよび12カラムのグリッドを用意しています。
2カラム
4カラム
<!-- 2カラム -->
<div class="grid grid-cols-2">...</div>
<!-- 3カラム -->
<div class="grid grid-cols-3">...</div>
<!-- 4カラム -->
<div class="grid grid-cols-4">...</div>
カラムスパン
特定の要素を複数のカラムにまたがせることができます。
<div class="grid grid-cols-4 gap-md">
<div class="col-span-2">2カラム分</div>
<div>1</div>
<div>2</div>
<div>3</div>
<div class="col-span-3">3カラム分</div>
</div>
レスポンシブグリッド
画面サイズに応じてカラム数を変更できます。sm:、md:、lg: プレフィックスを使用します。
<!-- モバイル: 1カラム, タブレット: 2カラム, デスクトップ: 3-4カラム -->
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
</div>
ギャップのバリエーション
要素間の間隔を調整できます。.gap-sm、.gap-md、.gap-lg、.gap-xl が利用可能です。
gap-sm
gap-xl
.gap-sm { gap: var(--spacing-sm); } /* 0.5rem */
.gap-md { gap: var(--spacing-md); } /* 1rem */
.gap-lg { gap: var(--spacing-lg); } /* 1.5rem */
.gap-xl { gap: var(--spacing-xl); } /* 2rem */
テーブル
データを表形式で表示する場合に使用します。料金表、仕様比較、データ一覧などに適しています。
基本的なテーブル
料金プラン、サービス比較、技術仕様などの表示に使用します。
| プラン | データ容量 | 月額料金 | 対象 |
|---|---|---|---|
| ライトプラン | 1GB | ¥1,000 | 小規模IoT |
| スタンダードプラン | 5GB | ¥3,000 | 中規模IoT |
| プロプラン | 20GB | ¥8,000 | 大規模IoT |
| エンタープライズ | 無制限 | 要相談 | 法人向け |
<div class="table-wrapper">
<table>
<thead>
<tr>
<th>プラン</th>
<th>データ容量</th>
<th>月額料金</th>
<th>対象</th>
</tr>
</thead>
<tbody>
<tr>
<td>ライトプラン</td>
<td>1GB</td>
<td>¥1,000</td>
<td>小規模IoT</td>
</tr>
<!-- 他の行... -->
</tbody>
</table>
</div>
table {
width: 100%;
border-collapse: collapse;
background-color: var(--color-surface);
border-radius: 0.5rem;
overflow: hidden;
}
thead {
background-color: var(--color-background-alt);
}
th {
padding: var(--spacing-md);
text-align: left;
font-weight: var(--font-weight-semibold);
border-bottom: 2px solid var(--color-border);
}
td {
padding: var(--spacing-md);
border-bottom: 1px solid var(--color-border-light);
}
tbody tr:hover {
background-color: var(--color-background-alt);
}
コンパクトテーブル
.table-compact クラスを追加すると、セル幅が小さくなります。
SIM一覧など、多数のレコードを表示する場合に適しています。
| SIM ID | 電話番号 | 契約状態 | データ使用量 | プラン | 登録日 |
|---|---|---|---|---|---|
| SIM-001 | 090-1234-5678 | ● アクティブ | 2.3GB | ライト | 2025-01-15 |
| SIM-002 | 090-2345-6789 | ● アクティブ | 4.1GB | スタンダード | 2025-02-20 |
| SIM-003 | 090-3456-7890 | ● 停止中 | 0.0GB | ライト | 2025-03-10 |
| SIM-004 | 090-4567-8901 | ● アクティブ | 15.7GB | プロ | 2025-04-05 |
| SIM-005 | 090-5678-9012 | ● 解約済 | 0.0GB | - | 2025-05-12 |
<div class="table-wrapper table-compact">
<table>
<!-- テーブルの内容 -->
</table>
</div>
ヘッダー固定テーブル
.table-fixed-header クラスを追加すると、ヘッダーを固定して縦スクロールできます。
多数のレコードを一覧表示する場合に適しています。
| デバイスID | デバイス名 | ステータス | 最終通信 | バッテリー |
|---|---|---|---|---|
| DEV-001 | 温度センサーA | ● オンライン | 2分前 | 95% |
| DEV-002 | 湿度センサーB | ● オンライン | 5分前 | 82% |
| DEV-003 | 圧力センサーC | ● 警告 | 30分前 | 45% |
| DEV-004 | 加速度センサーD | ● オンライン | 1分前 | 100% |
| DEV-005 | GPS トラッカーE | ● オフライン | 2時間前 | 0% |
| DEV-006 | 温度センサーF | ● オンライン | 3分前 | 88% |
| DEV-007 | 湿度センサーG | ● オンライン | 1分前 | 92% |
| DEV-008 | 圧力センサーH | ● オンライン | 4分前 | 76% |
| DEV-009 | 加速度センサーI | ● オンライン | 2分前 | 91% |
| DEV-010 | GPS トラッカーJ | ● オンライン | 1分前 | 85% |
<div class="table-wrapper table-fixed-header">
<table>
<!-- ヘッダーが固定され、テーブル本体がスクロール可能 -->
</table>
</div>
横スクロール対応テーブル
.table-scroll クラスを追加すると、横幅が広いテーブルを横スクロールできます。
カラム数が多い場合に適しています。
| ID | 会社名 | 担当者 | 電話番号 | メール | 契約プラン | 契約開始日 | SIM数 | 月額料金 | ステータス |
|---|---|---|---|---|---|---|---|---|---|
| 001 | 株式会社サンプル | 田中 太郎 | 03-1234-5678 | tanaka@sample.co.jp | エンタープライズ | 2024-01-15 | 50 | ¥150,000 | ● アクティブ |
| 002 | テスト株式会社 | 佐藤 花子 | 03-2345-6789 | sato@test.co.jp | プロ | 2024-03-20 | 10 | ¥30,000 | ● アクティブ |
| 003 | デモ有限会社 | 鈴木 次郎 | 03-3456-7890 | suzuki@demo.co.jp | スタンダード | 2024-05-10 | 5 | ¥15,000 | ● 支払遅延 |
<div class="table-wrapper table-scroll">
<table>
<!-- 横幅が広いテーブルは横スクロール可能 -->
</table>
</div>
/* コンパクト */
.table-compact th,
.table-compact td {
padding: var(--spacing-sm) var(--spacing-md);
font-size: var(--font-size-sm);
}
/* ヘッダー固定 */
.table-fixed-header {
max-height: 400px;
overflow-y: auto;
}
.table-fixed-header thead {
position: sticky;
top: 0;
z-index: 10;
}
/* 横スクロール */
.table-scroll {
overflow-x: auto;
}
.table-scroll table {
min-width: 800px;
}
ヘッダー固定 + 横スクロール併用
.table-fixed-header と .table-scroll を同時に使用すると、
縦横両方向にスクロール可能なテーブルになります。SIM詳細一覧など、多数のレコード・多数のカラムを持つテーブルに最適です。
| SIM ID | ICCID | 電話番号 | 契約状態 | データ使用量 | プラン | 月額料金 | 登録日 | 最終通信 | アクション |
|---|---|---|---|---|---|---|---|---|---|
| SIM-001 | 8981100000123456789 | 090-1234-5678 | ● アクティブ | 2.3GB / 5GB | スタンダード | ¥3,000 | 2025-01-15 | 2分前 | |
| SIM-002 | 8981100000234567890 | 090-2345-6789 | ● アクティブ | 0.8GB / 1GB | ライト | ¥1,000 | 2025-02-20 | 5分前 | |
| SIM-003 | 8981100000345678901 | 090-3456-7890 | ● 停止中 | 0.0GB / 5GB | スタンダード | ¥3,000 | 2025-03-10 | 3日前 | |
| SIM-004 | 8981100000456789012 | 090-4567-8901 | ● アクティブ | 15.7GB / 20GB | プロ | ¥8,000 | 2025-04-05 | 1分前 | |
| SIM-005 | 8981100000567890123 | 090-5678-9012 | ● 解約済 | 0.0GB / - | - | - | 2025-05-12 | - | |
| SIM-006 | 8981100000678901234 | 090-6789-0123 | ● アクティブ | 4.2GB / 5GB | スタンダード | ¥3,000 | 2025-06-01 | 10分前 | |
| SIM-007 | 8981100000789012345 | 090-7890-1234 | ● アクティブ | 18.5GB / 20GB | プロ | ¥8,000 | 2025-07-10 | 3分前 | |
| SIM-008 | 8981100000890123456 | 090-8901-2345 | ● アクティブ | 0.5GB / 1GB | ライト | ¥1,000 | 2025-08-15 | 7分前 | |
| SIM-009 | 8981100000901234567 | 090-9012-3456 | ● 警告 | 4.8GB / 5GB | スタンダード | ¥3,000 | 2025-09-20 | 15分前 | |
| SIM-010 | 8981100001012345678 | 090-0123-4567 | ● アクティブ | 12.3GB / 20GB | プロ | ¥8,000 | 2025-10-05 | 2分前 |
<!-- ヘッダー固定 + 横スクロール -->
<div class="table-wrapper table-fixed-header table-scroll table-compact">
<table>
<!-- 縦横両方向にスクロール可能 -->
</table>
</div>
リスト
クリック可能なアイテム、アイコン、アクションボタンを持つアクションリストコンポーネントです。 設定画面、ナビゲーションメニュー、データ一覧などに使用します。
基本的なリスト
アイコン、タイトル、説明、アクションを持つ基本的なリストです。
-
プロフィール 名前、メールアドレスの編集
-
設定 アプリケーションの設定
-
通知 通知の設定
<ul class="action-list list-bordered list-medium">
<li class="list-item clickable">
<span class="list-item-icon">
<!-- アイコン -->
</span>
<div class="list-item-content">
<span class="list-item-title">プロフィール</span>
<span class="list-item-description">説明文</span>
</div>
<span class="list-item-action">
<!-- 矢印アイコンなど -->
</span>
</li>
</ul>
リストのバリエーション
3つのバリエーション(デフォルト、ボーダー付き、区切り線付き)を使い分けます。
ボーダー付き(list-bordered)
-
アカウント
-
セキュリティ
区切り線付き(list-divided)
-
アカウント
-
セキュリティ
<!-- ボーダー付き -->
<ul class="action-list list-bordered list-medium">...</ul>
<!-- 区切り線付き -->
<ul class="action-list list-divided list-medium">...</ul>
リストアイテムの状態
選択状態、無効状態など、様々な状態を表現できます。
-
通常状態 クリック可能なアイテム
-
選択状態 選択されているアイテム
-
無効状態 クリックできないアイテム
<!-- 選択状態 -->
<li class="list-item clickable selected">...</li>
<!-- 無効状態 -->
<li class="list-item clickable disabled">...</li>
リストのサイズ
3つのサイズ(small、medium、large)を使い分けます。
Small
-
プロフィール
-
設定
Large
-
プロフィール
-
設定
<!-- Small -->
<ul class="action-list list-bordered list-small">...</ul>
<!-- Medium (デフォルト) -->
<ul class="action-list list-bordered list-medium">...</ul>
<!-- Large -->
<ul class="action-list list-bordered list-large">...</ul>
.action-list {
list-style: none;
margin: 0;
padding: 0;
}
.list-item {
display: flex;
align-items: center;
gap: var(--spacing-md);
padding: var(--spacing-md);
background-color: var(--color-surface);
transition: background-color var(--transition-fast) ease;
}
.list-item.clickable {
cursor: pointer;
}
.list-item.clickable:hover {
background-color: var(--color-background-alt);
}
.list-item.selected {
background-color: color-mix(in srgb, var(--color-primary) 10%, transparent);
}
.list-item.disabled {
opacity: 0.5;
cursor: not-allowed;
}
ステッパー
マルチステッププロセスの進行状況を表示するコンポーネントです。 フォームウィザード、チェックアウトフロー、登録プロセスなどに使用します。
水平ステッパー
横方向にステップを表示します。画面幅に余裕がある場合に適しています。
<div class="stepper stepper-horizontal stepper-medium" data-current-step="1">
<ol class="stepper-list">
<li class="stepper-item completed">
<button type="button" class="stepper-button">
<span class="stepper-indicator">
<svg class="stepper-check-icon" viewBox="0 0 24 24">
<polyline points="20 6 9 17 4 12" />
</svg>
</span>
<span class="stepper-content">
<span class="stepper-label">アカウント作成</span>
</span>
</button>
<div class="stepper-connector"></div>
</li>
<li class="stepper-item current">...</li>
<li class="stepper-item upcoming">...</li>
</ol>
</div>
垂直ステッパー
縦方向にステップを表示します。モバイルや詳細な説明が必要な場合に適しています。
<div class="stepper stepper-vertical stepper-medium">
<ol class="stepper-list">
<li class="stepper-item completed">
<button type="button" class="stepper-button">
<span class="stepper-indicator">
<svg class="stepper-check-icon" viewBox="0 0 24 24">
<polyline points="20 6 9 17 4 12" />
</svg>
</span>
<span class="stepper-content">
<span class="stepper-label">アカウント作成</span>
<span class="stepper-description">メールアドレスとパスワードを入力</span>
</span>
</button>
<div class="stepper-connector"></div>
</li>
...
</ol>
</div>
サイズバリエーション
3つのサイズ(small、medium、large)から選択できます。
Small
Large
トースト通知
一時的なフィードバックメッセージを表示するコンポーネントです。 成功、エラー、警告、情報の4つのタイプがあります。
トーストのデモ
ボタンをクリックして各タイプのトーストを表示します。
// トーストを表示
const toast = MisoraDesignSystem.getToast();
// 成功メッセージ
toast.success('操作が正常に完了しました', '成功');
// エラーメッセージ
toast.error('エラーが発生しました', 'エラー');
// 警告メッセージ
toast.warning('この操作は取り消せません', '警告');
// 情報メッセージ
toast.info('新しいアップデートがあります', 'お知らせ');
// カスタムオプション
toast.show({
type: 'success',
title: 'タイトル',
message: 'メッセージ',
duration: 5000 // 表示時間(ミリ秒)
});
トーストのタイプ
4つのタイプを用途に応じて使い分けます。
<!-- 成功トースト -->
<div class="toast toast-success">
<div class="toast-icon">...</div>
<div class="toast-content">
<div class="toast-title">成功</div>
<div class="toast-message">操作が正常に完了しました</div>
</div>
<button class="toast-close">...</button>
</div>
<!-- エラートースト -->
<div class="toast toast-error">...</div>
<!-- 警告トースト -->
<div class="toast toast-warning">...</div>
<!-- 情報トースト -->
<div class="toast toast-info">...</div>
表示位置
トーストコンテナに位置クラスを追加することで、6つの位置から選択できます。
/* 位置クラス */
.toast-container.toast-top-right /* 右上(デフォルト) */
.toast-container.toast-top-left /* 左上 */
.toast-container.toast-top-center /* 上中央 */
.toast-container.toast-bottom-right /* 右下 */
.toast-container.toast-bottom-left /* 左下 */
.toast-container.toast-bottom-center /* 下中央 */
/* カスタム初期化 */
MisoraDesignSystem.initToast({ position: 'bottom-right' });
カード
関連する情報をグループ化して表示するコンテナです。 サービス紹介、機能説明、ブログ記事のプレビューなどに使用します。
基本的なカード
コンテンツをグループ化し、視覚的に分離して表示します。
<div class="card">
<h4>カードタイトル</h4>
<p>カードの説明文がここに入ります。</p>
<a href="#">詳細を見る →</a>
</div>
.card {
background-color: var(--color-surface);
border: 1px solid var(--color-border-light);
border-radius: 0.5rem;
padding: var(--spacing-xl);
box-shadow: var(--shadow-sm);
transition: box-shadow 0.3s ease, transform 0.3s ease;
}
.card:hover {
box-shadow: var(--shadow-md);
transform: translateY(-2px);
}