@charset "UTF-8";
/**
 * Goodly シェル — フッターの端末。
 *
 * 緑on黒の「いかにも」な端末にはしない。プロンプトはサイトのオレンジ
 * (--kabocy-color-primary 系) で、地は温かみのある暗色。どこの端末でもなく
 * goodly.jp の端末に見えることが狙い。
 */

.gsh {
	--gsh-bg: #1b1a18;
	--gsh-bar: #2a2825;
	--gsh-fg: #ebe5db;
	--gsh-dim: #9a9186;
	--gsh-accent: #ff8a3d;
	--gsh-ok: #8ad48f;
	--gsh-edge: rgba(255, 255, 255, .09);
	/* ls --color=auto と grep --color=auto の色。本物の端末の既定に寄せる。 */
	--gsh-dir: #7fb4ff;
	--gsh-lnk: #6fd6d6;
	--gsh-hit: #ff6b6b;

	position: relative;
	max-width: 960px;
	margin: 0 auto 40px;
	border-radius: 12px;
	overflow: hidden;
	background: var(--gsh-bg);
	box-shadow: 0 18px 44px rgba(0, 0, 0, .34);
	font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, "Noto Sans Mono CJK JP", monospace;
	font-size: 13px;
	line-height: 1.75;
	color: var(--gsh-fg);
	text-align: left;
}

/*
 * パレット。`theme` で切り替え、localStorage に残る。
 *
 * 既定（goodly）以外はどれも「どこかで見た端末」で、それが狙い。見つけた人が
 * 自分の端末に寄せられることに意味があるので、奇を衒わず定番だけ置く。
 * 変えるのは .gsh のカスタムプロパティだけなので、部品側は何も知らなくていい。
 */
.gsh[data-palette="green"] {
	--gsh-bg: #05120a;
	--gsh-bar: #0b2014;
	--gsh-fg: #b8f5c4;
	--gsh-dim: #5f9a71;
	--gsh-accent: #4ade80;
	--gsh-ok: #86efac;
	--gsh-edge: rgba(134, 239, 172, .16);
	--gsh-dir: #4ade80;
	--gsh-lnk: #d9fbe1;
	--gsh-hit: #fef08a;
}

.gsh[data-palette="amber"] {
	--gsh-bg: #150f04;
	--gsh-bar: #241a08;
	--gsh-fg: #ffd79a;
	--gsh-dim: #a3814a;
	--gsh-accent: #ffb23d;
	--gsh-ok: #ffd79a;
	--gsh-edge: rgba(255, 178, 61, .16);
	--gsh-dir: #ffb23d;
	--gsh-lnk: #ffe7c2;
	--gsh-hit: #fff4d6;
}

.gsh[data-palette="mono"] {
	--gsh-bg: #0d0d0d;
	--gsh-bar: #1a1a1a;
	--gsh-fg: #f2f2f2;
	--gsh-dim: #9a9a9a;
	--gsh-accent: #ffffff;
	--gsh-ok: #d8d8d8;
	--gsh-edge: rgba(255, 255, 255, .18);
	--gsh-dir: #ffffff;
	--gsh-lnk: #d8d8d8;
	--gsh-hit: #ffffff;
}

/* --- apt install の進捗 -------------------------------------------------- */
/*
 * 見せかけの進捗だが、最後に着く先は本物のガイド。だから「それらしく待たせる」
 * ことに意味がある。動きを控える設定では待たせず、即座に結果だけ出す。
 */
.gsh__bar-line {
	display: flex;
	align-items: center;
	gap: 10px;
	margin: 2px 0;
	font-variant-numeric: tabular-nums;
}

.gsh__bar-track {
	flex: 1 1 160px;
	max-width: 240px;
	height: 8px;
	border: 1px solid var(--gsh-edge);
	border-radius: 999px;
	overflow: hidden;
	background: rgba(255, 255, 255, .05);
}

.gsh__bar-fill {
	display: block;
	height: 100%;
	width: 0;
	background: var(--gsh-accent);
}

/* --- 実績 ----------------------------------------------------------------- */
.gsh__badge {
	color: var(--gsh-ok);
	font-weight: 700;
}

.gsh__locked {
	color: var(--gsh-dim);
}

/* --- タイトルバー ------------------------------------------------------- */
.gsh__bar {
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 9px 14px;
	background: var(--gsh-bar);
	border-bottom: 1px solid var(--gsh-edge);
}

.gsh__dots {
	display: inline-flex;
	gap: 7px;
}

.gsh__dots i {
	width: 11px;
	height: 11px;
	border-radius: 50%;
	background: #57534e;
}

.gsh__dots i:nth-child(1) { background: #ff5f57; }
.gsh__dots i:nth-child(2) { background: #febc2e; }
.gsh__dots i:nth-child(3) { background: #28c840; }

.gsh__title {
	color: var(--gsh-dim);
	font-size: 12px;
	letter-spacing: .02em;
}

/* --- 画面 --------------------------------------------------------------- */
.gsh__screen {
	padding: 16px 18px 18px;
}

/*
 * Tux の居場所を空ける。実測で実行ボタンとヒント行に重なっていた。
 * 絶対配置のものを後ろに置くなら、前のものが下に回り込まないよう
 * 場所そのものを確保するのが確実。
 */
@media (min-width: 721px) {
	.gsh__screen {
		padding-right: 104px;
	}
}

.gsh__motd {
	margin: 0 0 10px;
	/* 端末なので pre だが、狭い画面では折り返さないと横スクロールが出る。 */
	white-space: pre-wrap;
	word-break: break-word;
	font: inherit;
	color: var(--gsh-fg);
}

.gsh__dim { color: var(--gsh-dim); }
.gsh__accent { color: var(--gsh-accent); font-weight: 700; }
.gsh__num { color: var(--gsh-ok); font-variant-numeric: tabular-nums; }

.gsh__daily {
	margin: 0 0 12px;
	padding: 0;
	list-style: none;
	display: grid;
	gap: 3px;
}

.gsh__daily li {
	display: flex;
	flex-wrap: wrap;
	gap: 0 10px;
	align-items: baseline;
}

.gsh__daily a {
	color: var(--gsh-accent);
	font-weight: 700;
	text-decoration: none;
	border-bottom: 1px dotted currentColor;
}

.gsh__daily a:hover,
.gsh__daily a:focus-visible {
	color: #ffb27a;
}

/* --- 出力 --------------------------------------------------------------- */
.gsh__log {
	max-height: 250px;
	overflow-y: auto;
	overscroll-behavior: contain;
}

.gsh__log:not(:empty) {
	margin: 0 0 8px;
	padding-top: 8px;
	border-top: 1px solid var(--gsh-edge);
}

.gsh__log p {
	margin: 0;
	white-space: pre-wrap;
	word-break: break-word;
}

.gsh__log a {
	color: var(--gsh-accent);
	text-decoration: underline;
}

.gsh__echo { color: var(--gsh-dim); }
.gsh__err { color: #ff9f8f; }

/*
 * 標準出力。複数行を1つの <pre> で出す。
 *
 * 既定は折り返す（本物の端末も、幅を超えた行は折り返す）。桁を揃える出力
 * （ls -l・df・neofetch）だけは折り返すと表でなくなるので、横に流す。
 * 以前はこの手の出力を ASCII アートと同じ扱いにして読み上げから隠していた。
 */
.gsh__out {
	margin: 0;
	font: inherit;
	white-space: pre-wrap;
	word-break: break-word;
	color: var(--gsh-fg);
}

.gsh__out--table {
	line-height: 1.5;
	white-space: pre;
	word-break: normal;
	overflow-x: auto;
}

.gsh__ls-dir { color: var(--gsh-dir); font-weight: 700; }
.gsh__log a.gsh__ls-lnk { color: var(--gsh-lnk); }
.gsh__hit { color: var(--gsh-hit); font-weight: 700; }

/* 色だけでは区別できないパレットでは、形でも分ける。 */
.gsh[data-palette="mono"] .gsh__hit { text-decoration: underline; }

/*
 * man ページ。字下げは空白ではなく余白で付ける — 空白だと、折り返した
 * 2行目が左端に戻る。本物の man と同じ 7 桁・14 桁。狭い画面では詰める。
 */
.gsh__man {
	margin: 2px 0;
	white-space: pre-wrap;
	word-break: break-word;
	color: var(--gsh-fg);
}

.gsh__man-row {
	display: flex;
	justify-content: space-between;
	gap: 1ch;
}

.gsh__man-h { font-weight: 700; }
.gsh__man b { font-weight: 700; }
.gsh__man-1 { padding-left: 7ch; }
.gsh__man-2 { padding-left: 14ch; }
.gsh__man-hang { padding-left: 14ch; text-indent: -7ch; }

@media (max-width: 480px) {
	.gsh__man-1 { padding-left: 3ch; }
	.gsh__man-2 { padding-left: 6ch; }
	.gsh__man-hang { padding-left: 10ch; text-indent: -7ch; }
}

/*
 * スマホの補助キー。指で操作する端末で、入力欄にフォーカスがあるときだけ出す。
 * 押してもフォーカスは入力欄に残す（JS 側）。
 */
.gsh__keys {
	display: none;
	gap: 6px;
	padding: 2px 0 8px;
	overflow-x: auto;
	scrollbar-width: none;
}

.gsh__keys button {
	flex: 0 0 auto;
	min-width: 44px;
	min-height: 36px;
	padding: 4px 10px;
	border: 1px solid var(--gsh-edge);
	border-radius: 6px;
	background: var(--gsh-bar);
	color: var(--gsh-fg);
	font: inherit;
	cursor: pointer;
	-webkit-tap-highlight-color: transparent;
}

.gsh__keys button:active { background: var(--gsh-edge); }
.gsh__keys button:focus-visible { outline: 2px solid var(--gsh-accent); outline-offset: 1px; }

@media (pointer: coarse) {
	.gsh:focus-within .gsh__keys { display: flex; }
}

/*
 * ページャ（less / more / man）。開いている間は出力欄などを隠し、本物の less の
 * 別画面のように見せる。閉じると元に戻り、ページは何も残さない。
 * 下の行は less と同じ反転表示。
 */
.gsh.is-paging .gsh__screen > :not(.gsh__pager):not(.gsh__prompt) { display: none; }

.gsh__pager {
	margin: 0 0 8px;
	padding-top: 8px;
	border-top: 1px solid var(--gsh-edge);
}

.gsh__pager-body {
	position: relative;
	height: min(62vh, 30em);
	overflow-y: auto;
	overscroll-behavior: contain;
	white-space: pre-wrap;
	word-break: break-word;
	outline: none;
}

.gsh__pager-body:focus-visible { box-shadow: inset 0 0 0 1px var(--gsh-accent); }
.gsh__pager-body > .is-hit { background: var(--gsh-edge); }

.gsh__pager-bar {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 8px;
	margin-top: 6px;
}

.gsh__pager-status {
	min-width: 0;
	padding: 0 4px;
	overflow: hidden;
	background: var(--gsh-fg);
	color: var(--gsh-bg);
	white-space: nowrap;
	text-overflow: ellipsis;
}

.gsh__pager-keys {
	display: flex;
	flex: 0 0 auto;
	gap: 4px;
}

.gsh__pager-keys button {
	min-width: 32px;
	min-height: 28px;
	padding: 0 8px;
	border: 1px solid var(--gsh-edge);
	border-radius: 6px;
	background: var(--gsh-bar);
	color: var(--gsh-fg);
	font: inherit;
	cursor: pointer;
}

.gsh__pager-keys button:focus-visible { outline: 2px solid var(--gsh-accent); outline-offset: 1px; }

@media (pointer: coarse) {
	.gsh__pager-keys button { min-width: 40px; min-height: 36px; }
}

/* 1行ずつ出てくるほうが「返ってきた」感じになる。距離は3pxで十分。 */
.gsh__log > * {
	animation: gsh-in .18s ease-out both;
}

@keyframes gsh-in {
	from { opacity: 0; transform: translateY(3px); }
	to { opacity: 1; transform: none; }
}

/* --- フッター本体の区切り ------------------------------------------------ */
/*
 * 端末のコメント行に見せる区切り。`─` を並べた文字列にすると狭い画面で
 * 折り返して2行になるので、線は罫線で引いてラベルだけ文字にする。
 * 読み上げには要らないので aria-hidden（マークアップ側で付けている）。
 */
.gsh-rule {
	display: flex;
	align-items: center;
	gap: 14px;
	max-width: 960px;
	margin: 0 auto 24px;
	color: #9a9186;
	font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
	font-size: 12px;
	letter-spacing: .04em;
}

.gsh-rule::before,
.gsh-rule::after {
	content: "";
	flex: 1;
	border-top: 1px dashed rgba(255, 255, 255, .2);
}

.gsh-rule span { white-space: nowrap; }

/* --- ASCII ------------------------------------------------------------- */
/*
 * アートは折り返した瞬間に絵ではなくなる。だから pre のまま、狭い画面では
 * 横に送れるようにする（本文の折り返し方針とはここだけ意図的に違う）。
 */
.gsh__art {
	margin: 2px 0;
	font: inherit;
	line-height: 1.35;
	white-space: pre;
	overflow-x: auto;
	color: var(--gsh-fg);
}

.gsh__matrix { color: var(--gsh-ok); }

/* sl。ログの中を通過させるので、はみ出しは隠す。 */
.gsh__rail {
	overflow: hidden;
	margin: 4px 0;
}

.gsh__train {
	display: inline-block;
	overflow: visible;
	color: var(--gsh-accent);
	animation: gsh-sl 4s linear forwards;
}

@keyframes gsh-sl {
	from { transform: translateX(100%); }
	to { transform: translateX(-100%); }
}

/* --- プロンプト --------------------------------------------------------- */
.gsh__prompt {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 8px;
}

.gsh__ps1 {
	color: var(--gsh-accent);
	font-weight: 700;
	white-space: nowrap;
}

/*
 * 待っている端末のカーソル。フォーカスすると本物のキャレットに主役を譲るので、
 * `:focus-within` で消すだけでよく、JS の状態管理が要らない。
 */
.gsh__caret {
	color: var(--gsh-accent);
	animation: gsh-blink 1.1s step-end infinite;
	margin-left: -4px;
}

.gsh__prompt:focus-within .gsh__caret {
	display: none;
}

@keyframes gsh-blink {
	0%, 50% { opacity: 1; }
	50.01%, 100% { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
	.gsh__caret { animation: none; }
}

.gsh__notice {
	margin: 0 0 10px;
	color: var(--gsh-fg);
}

/*
 * 季節の一語。絵を差し替えるのではなく、肩に一つ載せるだけにする。
 * 毎年の手入れが要らないのと、パレットを変えても壊れないのが理由。
 */
.gsh__season {
	margin: 0 0 10px;
	color: var(--gsh-dim);
}

.gsh__tux-mark {
	position: absolute;
	right: -2px;
	top: -4px;
	font-size: 20px;
	line-height: 1;
	filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .5));
}


.gsh__input {
	flex: 1 1 200px;
	min-width: 0;
	/* iOS は16px未満の入力にフォーカスすると画面を拡大して戻さない。 */
	font: inherit;
	font-size: 16px;
	padding: 6px 2px;
	color: var(--gsh-fg);
	background: transparent;
	border: 0;
	border-bottom: 1px solid var(--gsh-edge);
	border-radius: 0;
	caret-color: var(--gsh-accent);
}

.gsh__input::placeholder { color: #6f675e; }

.gsh__input:focus {
	outline: none;
	border-bottom-color: var(--gsh-accent);
}

.gsh__go {
	min-height: 36px;
	padding: 0 14px;
	border: 1px solid var(--gsh-edge);
	border-radius: 7px;
	background: #322f2b;
	color: var(--gsh-fg);
	font: inherit;
	cursor: pointer;
}

.gsh__go:hover,
.gsh__go:focus-visible {
	background: #3d3935;
	border-color: var(--gsh-accent);
}

/* --- 試してみる --------------------------------------------------------- */
.gsh__hint {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 8px;
	margin: 12px 0 0;
	font-size: 12px;
}

.gsh__chip {
	min-height: 30px;
	padding: 0 10px;
	border: 1px solid var(--gsh-edge);
	border-radius: 999px;
	background: transparent;
	color: var(--gsh-dim);
	font: inherit;
	font-size: 12px;
	cursor: pointer;
}

.gsh__chip:hover,
.gsh__chip:focus-visible {
	color: var(--gsh-fg);
	border-color: var(--gsh-accent);
}

/* --- Tux ---------------------------------------------------------------- */
.gsh__tux {
	position: absolute;
	right: 14px;
	bottom: 10px;
	width: 72px;
	height: 72px;
	padding: 0;
	border: 0;
	background: transparent;
	cursor: pointer;
	opacity: .5;
	transition: opacity .2s ease, transform .2s ease;
	pointer-events: auto;
}

.gsh__tux:hover { opacity: .95; }
.gsh__tux img { display: block; width: 100%; height: auto; }

/* つつかれたときの一往復。CSS だけで完結させる。 */
.gsh__tux.is-poked { animation: gsh-poke .5s cubic-bezier(.22, 1, .36, 1); }

@keyframes gsh-poke {
	30% { transform: translateY(-9px) rotate(-7deg); }
	60% { transform: translateY(0) rotate(5deg); }
	100% { transform: none; }
}

/* Tux は装飾。狭い画面では入力欄に重なるので出さない。 */
@media (max-width: 720px) {
	.gsh__tux { display: none; }
	.gsh { font-size: 12.5px; }
	.gsh__screen { padding: 14px; }
}

/* --- 起動 --------------------------------------------------------------- */
/*
 * 画面に入るまで JS が何もしないので、初期状態は「消えている」ではなく
 * 「そのまま読める」。動くのは一度きりで、届かなくても内容は読める。
 */
.gsh.is-booting .gsh__screen > * {
	animation: gsh-boot .34s ease-out both;
}

.gsh.is-booting .gsh__motd { animation-delay: .04s; }
.gsh.is-booting .gsh__daily { animation-delay: .12s; }
.gsh.is-booting .gsh__prompt { animation-delay: .2s; }
.gsh.is-booting .gsh__hint { animation-delay: .26s; }

@keyframes gsh-boot {
	from { opacity: 0; transform: translateY(6px); }
	to { opacity: 1; transform: none; }
}

/* 走っていく Tux（Konami）。画面外から画面外へ。 */
.gsh__runner {
	position: fixed;
	left: -120px;
	bottom: 12px;
	width: 84px;
	z-index: 9999;
	pointer-events: none;
	animation: gsh-run 2.6s linear forwards;
}

@keyframes gsh-run {
	to { transform: translateX(calc(100vw + 220px)); }
}

/* トースト（vim ネタなど）。 */
.gsh__toast {
	position: fixed;
	left: 50%;
	bottom: 26px;
	z-index: 9999;
	transform: translateX(-50%);
	max-width: min(92vw, 420px);
	padding: 12px 18px;
	border-radius: 10px;
	background: #1b1a18;
	color: #ebe5db;
	border: 1px solid rgba(255, 255, 255, .14);
	box-shadow: 0 12px 30px rgba(0, 0, 0, .4);
	font-size: 14px;
	text-align: center;
	animation: gsh-toast 2.8s ease-out forwards;
}

@keyframes gsh-toast {
	0% { opacity: 0; transform: translate(-50%, 10px); }
	12%, 80% { opacity: 1; transform: translate(-50%, 0); }
	100% { opacity: 0; transform: translate(-50%, -6px); }
}

@media (prefers-reduced-motion: reduce) {
	.gsh__train { animation: none; }

	.gsh.is-booting .gsh__screen > *,
	.gsh__log > *,
	.gsh__tux.is-poked,
	.gsh__runner,
	.gsh__toast {
		animation: none;
	}

	.gsh__runner { display: none; }
	.gsh__toast { opacity: 1; }
}
