---
title: "Hortulus"
date: 2026-03-02
date-format: "令和8年M月D日"
---
```{=html}
<div class="author-block">
<span class="author-name">午 前 五 時</span>
<svg class="author-seal-svg" viewBox="0 0 120 120"
xmlns="http://www.w3.org/2000/svg" role="img" aria-label="印鑑: 造園担当国務大令印">
<circle cx="60" cy="60" r="56" fill="none"
stroke="currentColor" stroke-width="3.5"/>
<circle cx="60" cy="60" r="49" fill="none"
stroke="currentColor" stroke-width="0.8"/>
<g font-family="HakushuTensho" fill="currentColor" text-anchor="middle">
<text x="81.0" y="34.0" font-size="22.3" dy="0.35em">造</text>
<text x="81.0" y="60.0" font-size="22.3" dy="0.35em">園</text>
<text x="81.0" y="86.2" font-size="22.3" dy="0.35em">担</text>
<text x="60.2" y="33.8" font-size="22.3" dy="0.35em">当</text>
<text x="60.0" y="60.0" font-size="22.3" dy="0.35em">国</text>
<text x="59.8" y="86.2" font-size="22.3" dy="0.35em">務</text>
<text x="39.0" y="33.8" font-size="22.3" dy="0.35em">大</text>
<text x="39.0" y="60.0" font-size="22.3" dy="0.35em">令</text>
<text x="39.2" y="86.4" font-size="22.3" dy="0.35em">印</text>
</g>
</svg>
</div>
<!-- 未認証向け: ページ上部の案内バナー -->
<div id="auth-banner" class="auth-banner">
<p>本コンテンツの閲覧には Google アカウントでのログインが必要です。ログインの前に、下記の「注意」と「姿勢」をご確認ください。</p>
<a href="#ログイン" class="auth-banner-link">ログインへ進む ↓</a>
</div>
```
## 概要 {.unnumbered}
Hortulus(ホルトゥルス)は、ラテン語で「小さな庭」を意味します。
ここでは、私の箱庭である架空国家「(名称未定)」の設定資料を公開しています。
## 注意 {.unnumbered}
以下の内容をご理解・ご了承いただける方のみ、コンテンツにアクセスしてください。
本コンテンツの内容は、**すべて創作(フィクション)**です。登場する国家・制度・文化・組織・人物・出来事などは架空であり、現実に存在する国、地域、団体、官公庁、宗教、民族、人物、事件等とは一切関係ありません。
また、世界観の構築にあたり、現実の行政機構や組織名称(例:「○○省」「○○局」「○○部」等)を参考として、そのまま、または一部改変して用いることがあります。
ただし、これらは創作上の便宜として借用したものであり、現実の組織・職務・政策・見解・活動を反映・代弁するものではありません。現実との類似がある場合も、意図的な主張ではなく創作上の演出としてご理解ください。
## 姿勢 {.unnumbered}
- 特定のイデオロギーや政治的立場を支持・批判する意図はありません。
- 整合性や現実性よりも創作上の演出を重視します。
- 差別や暴力、憎悪を正当化・助長する意図は一切ありません。
## ログイン {.unnumbered}
```{=html}
<section id="hortulus-auth" class="hortulus-auth">
<!-- Google でサインイン。JS が動かなくてもフォームは見える。 -->
<div id="auth-signin" class="auth-signin" data-consent="false">
<p class="auth-guidance">上記の「注意」と「姿勢」に同意のうえ、Google アカウントでログインしてください。</p>
<label class="auth-consent" for="auth-consent-checkbox">
<input id="auth-consent-checkbox" class="auth-consent-checkbox" type="checkbox" />
<span>「注意」と「姿勢」の内容に同意します</span>
</label>
<div id="g_id_onload"
data-client_id="404128773585-juu788seqei86hanh1dmugba3as05dob.apps.googleusercontent.com"
data-callback="handleGoogleCredential"
data-auto_prompt="false">
</div>
<div id="auth-signin-button" class="auth-signin-button" aria-disabled="true">
<div class="g_id_signin"
data-type="standard"
data-shape="rectangular"
data-theme="outline"
data-text="signin_with"
data-size="large"
data-locale="ja">
</div>
</div>
<p class="auth-consent-note">同意にチェックを入れるとログインボタンが有効になります。</p>
<div id="signin-error" class="auth-msg auth-msg--error" role="alert" hidden></div>
</div>
<!-- ログイン済み: 各篇への導線 -->
<div id="auth-content-links" hidden>
<p class="auth-guidance">ログインしています。以下のコンテンツを閲覧できます。</p>
<ul class="content-links">
<li><a href="/hortulus/overview/">Overview</a></li>
<li><a href="/hortulus/governance/">Governance</a></li>
</ul>
</div>
</section>
<script src="https://accounts.google.com/gsi/client" async defer></script>
<script>
window.handleGoogleCredential = function handleGoogleCredential(response) {
var errorEl = document.getElementById('signin-error');
var consentCheckbox = document.getElementById('auth-consent-checkbox');
if (errorEl) errorEl.hidden = true;
if (!consentCheckbox || !consentCheckbox.checked) {
if (errorEl) {
errorEl.textContent = 'ログインするには、同意のチェックを入れてください。';
errorEl.hidden = false;
}
return;
}
fetch('/api/auth/google-login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'same-origin',
body: JSON.stringify({ credential: response.credential })
})
.then(function(res) { return res.json(); })
.then(function(json) {
if (json.ok) {
location.reload();
} else if (errorEl) {
errorEl.textContent = json.error || 'ログインに失敗しました。しばらくしてからもう一度お試しください。';
errorEl.hidden = false;
}
})
.catch(function() {
if (errorEl) {
errorEl.textContent = '通信エラーが発生しました。接続を確認のうえ、もう一度お試しください。';
errorEl.hidden = false;
}
});
};
(function() {
var authBanner = document.getElementById('auth-banner');
var authSignin = document.getElementById('auth-signin');
var authSigninButton = document.getElementById('auth-signin-button');
var consentCheckbox = document.getElementById('auth-consent-checkbox');
var authContentLinks = document.getElementById('auth-content-links');
var auth = window.__HORTULUS_AUTH__;
function syncConsentState() {
var checked = !!(consentCheckbox && consentCheckbox.checked);
if (authSignin) authSignin.dataset.consent = checked ? 'true' : 'false';
if (authSigninButton) authSigninButton.setAttribute('aria-disabled', checked ? 'false' : 'true');
}
if (consentCheckbox) {
consentCheckbox.addEventListener('change', syncConsentState);
syncConsentState();
}
if (auth && auth.publicId) {
if (authBanner) authBanner.hidden = true;
if (authSignin) authSignin.hidden = true;
if (authContentLinks) authContentLinks.hidden = false;
}
// ヘッダー右端に認証ステータスを注入
var tools = document.querySelector('.quarto-navbar-tools');
if (tools && auth && auth.publicId) {
var wrap = document.createElement('div');
wrap.className = 'hortulus-header-auth';
var idSpan = document.createElement('span');
idSpan.className = 'header-public-id';
idSpan.textContent = 'ID: ' + auth.publicId;
wrap.appendChild(idSpan);
var btn = document.createElement('button');
btn.className = 'header-logout-btn';
btn.type = 'button';
btn.textContent = 'ログアウト';
wrap.appendChild(btn);
tools.prepend(wrap);
btn.addEventListener('click', function() {
fetch('/api/auth/logout', { method: 'POST', credentials: 'same-origin' })
.then(function() { location.reload(); })
.catch(function() { location.reload(); });
});
}
})();
</script>
<style>
/* ── 上部バナー ────────────────────────────── */
.auth-banner {
margin: var(--lk-size-md, 1em) 0;
padding: 0.8em 1em;
background: rgba(0, 141, 166, 0.06);
border-left: 3px solid var(--c-primary, #008da6);
border-radius: 4px;
}
.auth-banner p {
margin: 0 0 0.4em;
font-size: var(--lk-fs-callout, 0.94em);
color: var(--neojp-text-primary, #23262b);
}
.auth-banner-link {
display: inline-block;
font-size: var(--lk-fs-callout, 0.94em);
font-weight: 500;
color: var(--c-primary, #008da6);
text-decoration: none;
}
.auth-banner-link:hover {
text-decoration: underline;
}
/* ── ログインセクション ────────────────────── */
.hortulus-auth {
margin: var(--lk-size-lg, 1.618em) 0;
max-width: 28em;
}
.auth-signin {
display: grid;
gap: var(--lk-size-xs, 0.382em);
}
.auth-consent {
display: flex;
align-items: flex-start;
gap: 0.65em;
font-size: var(--lk-fs-callout, 0.94em);
color: var(--neojp-text-primary, #23262b);
margin-bottom: var(--lk-size-xs, 0.382em);
cursor: pointer;
}
.auth-consent-checkbox {
margin-top: 0.18em;
accent-color: var(--c-primary, #008da6);
}
.auth-signin-button {
width: fit-content;
transition: opacity 0.16s ease, filter 0.16s ease;
}
.auth-signin[data-consent="false"] .auth-signin-button {
opacity: 0.45;
filter: grayscale(1);
pointer-events: none;
}
.auth-consent-note {
font-size: var(--lk-fs-label, 0.83em);
color: var(--neojp-text-secondary, #5d6670);
margin: 0;
}
.auth-signin[data-consent="true"] .auth-consent-note {
display: none;
}
/* ── ヘッダー内認証ステータス ──────────────── */
.quarto-navbar-tools {
display: flex !important;
flex-wrap: nowrap;
align-items: center;
gap: 0.75em;
}
.hortulus-header-auth {
display: flex;
align-items: center;
gap: 0.6em;
white-space: nowrap;
margin-right: 0.5em;
padding-left: 1em;
}
.header-public-id {
font-family: inherit;
font-size: 0.75em;
color: var(--bs-navbar-color, rgba(0,0,0,0.65));
background: none;
padding: 0;
border-radius: 0;
}
.header-logout-btn {
font-size: 0.75em;
padding: 0.25em 0.75em;
border: 1px solid var(--bs-border-color, rgba(0,0,0,0.2));
border-radius: 4px;
background: transparent;
color: var(--bs-navbar-color, rgba(0,0,0,0.65));
cursor: pointer;
font-family: inherit;
transition: border-color 0.16s, background-color 0.16s;
}
.header-logout-btn:hover {
border-color: var(--bs-navbar-color, rgba(0,0,0,0.65));
background-color: color-mix(in srgb, var(--bs-navbar-color, rgba(0,0,0,0.65)) 10%, transparent);
}
/* ── サインイン・エラー ────────────────────── */
.auth-guidance {
font-size: var(--lk-fs-callout, 0.94em);
color: var(--neojp-text-secondary, #5d6670);
margin-bottom: var(--lk-size-sm, 0.618em);
}
.auth-msg {
margin-top: var(--lk-size-xs, 0.382em);
padding: 0.35em 0.55em;
border-radius: 4px;
font-size: var(--lk-fs-label, 0.83em);
}
.auth-msg--error {
background: rgba(185,28,28,0.06);
border-left: 3px solid #b91c1c;
color: #b91c1c;
}
/* ── コンテンツリンク ──────────────────────── */
.content-links {
list-style: none;
padding: 0;
margin: 0.6em 0 0;
}
.content-links li {
margin: 0.3em 0;
}
.content-links a {
color: var(--c-primary, #008da6);
text-decoration: none;
font-weight: 500;
}
.content-links a:hover {
text-decoration: underline;
}
</style>
```
## リンク {.unnumbered}
[Hortulus](/hortulus/)