web/app/globals.cssblame
View source
cf89d3c1@import url('https://fonts.googleapis.com/css2?family=Libre+Caslon+Text:ital,wght@0,400;1,400&family=JetBrains+Mono:wght@400;500&display=swap');
3e3af552@import "tailwindcss";
135dfe53
135dfe54/* ── Light theme (default) ── */
135dfe55:root {
135dfe56 --bg-page: #faf8f5;
135dfe57 --bg-card: #f2efe9;
135dfe58 --bg-inset: #eae6df;
135dfe59 --bg-hover: #e2ddd5;
135dfe510 --bg-input: #ffffff;
135dfe511
135dfe512 --text-primary: #2c2824;
135dfe513 --text-secondary: #4a4540;
135dfe514 --text-muted: #7a746c;
135dfe515 --text-faint: #a09888;
135dfe516
135dfe517 --accent: #4d8a78;
135dfe518 --accent-hover: #3d7a68;
135dfe519 --accent-subtle: #e8f2ee;
135dfe520 --accent-text: #ffffff;
135dfe521
135dfe522 --border: #d9d3ca;
135dfe523 --border-subtle: #e8e3db;
135dfe524 --divide: #e2ddd580;
135dfe525
135dfe526 --status-open-bg: #e8f2ee;
135dfe527 --status-open-text: #2d6b56;
135dfe528 --status-open-border: #b0d4c5;
135dfe529 --status-merged-bg: #ede8f5;
135dfe530 --status-merged-text: #6b4fa0;
135dfe531 --status-merged-border: #c5b8dc;
135dfe532 --status-closed-bg: #f5e8e8;
135dfe533 --status-closed-text: #a05050;
135dfe534 --status-closed-border: #dcb8b8;
135dfe535
135dfe536 --error-bg: #f5e8e8;
135dfe537 --error-border: #dcb8b8;
135dfe538 --error-text: #a05050;
135dfe539
135dfe540 --code-bg: #f2efe9;
12ffdd441
12ffdd442 --diff-add-bg: rgba(46, 160, 67, 0.08);
12ffdd443 --diff-add-text: #1a7f37;
12ffdd444 --diff-del-bg: rgba(248, 81, 73, 0.08);
12ffdd445 --diff-del-text: #cf222e;
135dfe546}
135dfe547
135dfe548/* ── Dark theme (Photodesk warm) ── */
135dfe549[data-theme="dark"] {
135dfe550 --bg-page: #1a1918;
135dfe551 --bg-card: #242220;
135dfe552 --bg-inset: #2e2c29;
135dfe553 --bg-hover: #383532;
135dfe554 --bg-input: #2e2c29;
135dfe555
135dfe556 --text-primary: #e8e4df;
135dfe557 --text-secondary: #c4bfb8;
135dfe558 --text-muted: #9a948c;
135dfe559 --text-faint: #6b665f;
135dfe560
135dfe561 --accent: #7aab9c;
135dfe562 --accent-hover: #8dbdaf;
135dfe563 --accent-subtle: #2a3632;
135dfe564 --accent-text: #1a1918;
135dfe565
135dfe566 --border: #3a3835;
135dfe567 --border-subtle: #302e2b;
135dfe568 --divide: #3a383580;
135dfe569
135dfe570 --status-open-bg: #2a3632;
135dfe571 --status-open-text: #7aab9c;
135dfe572 --status-open-border: #3d5249;
135dfe573 --status-merged-bg: #2e2a38;
135dfe574 --status-merged-text: #a892cc;
135dfe575 --status-merged-border: #4a3d66;
135dfe576 --status-closed-bg: #382a2a;
135dfe577 --status-closed-text: #cc9292;
135dfe578 --status-closed-border: #664040;
135dfe579
135dfe580 --error-bg: #382a2a;
135dfe581 --error-border: #664040;
135dfe582 --error-text: #cc9292;
135dfe583
135dfe584 --code-bg: #242220;
12ffdd485
12ffdd486 --diff-add-bg: rgba(46, 160, 67, 0.15);
12ffdd487 --diff-add-text: #3fb950;
12ffdd488 --diff-del-bg: rgba(248, 81, 73, 0.15);
12ffdd489 --diff-del-text: #f85149;
135dfe590}
135dfe591
135dfe592/* ── Base styles ── */
8a2c7d493@media (pointer: fine) {
8a2c7d494 html {
8a2c7d495 scrollbar-gutter: stable both-edges;
8a2c7d496 }
a33b2b697}
a33b2b698
a33b2b699@supports not (scrollbar-gutter: stable) {
8a2c7d4100 @media (pointer: fine) {
8a2c7d4101 html {
8a2c7d4102 overflow-y: scroll;
8a2c7d4103 }
a33b2b6104 }
a33b2b6105}
a33b2b6106
135dfe5107body {
135dfe5108 font-family: 'Libre Caslon Text', 'Georgia', serif;
135dfe5109 background-color: var(--bg-page);
135dfe5110 color: var(--text-primary);
8a2c7d4111 overflow-x: hidden;
135dfe5112}
135dfe5113
10621c5114.grove-body {
10621c5115 height: 100dvh;
10621c5116 overflow: hidden;
10621c5117 display: flex;
10621c5118 flex-direction: column;
10621c5119}
10621c5120.grove-scroll {
10621c5121 flex: 1;
10621c5122 min-height: 0;
10621c5123 overflow: auto;
10621c5124 /* iOS momentum scrolling */
10621c5125 -webkit-overflow-scrolling: touch;
10621c5126}
10621c5127
135dfe5128code, pre, .font-mono, kbd, samp {
135dfe5129 font-family: 'JetBrains Mono', 'Menlo', monospace;
135dfe5130}
bf5fc33131
bf5fc33132/* ── Shimmer skeleton ── */
bf5fc33133@keyframes shimmer {
bf5fc33134 0% { background-position: -400px 0; }
bf5fc33135 100% { background-position: 400px 0; }
bf5fc33136}
bf5fc33137.skeleton {
bf5fc33138 background: linear-gradient(
bf5fc33139 90deg,
bf5fc33140 var(--bg-card) 0%,
bf5fc33141 var(--bg-hover) 40%,
bf5fc33142 var(--bg-card) 80%
bf5fc33143 );
bf5fc33144 background-size: 800px 100%;
bf5fc33145 animation: shimmer 1.5s ease-in-out infinite;
bf5fc33146}
bf5fc33147
a011f1e148/* ── Badge activity cue for running states ── */
fe3b509149@keyframes badge-running-border {
a011f1e150 0%, 100% {
fe3b509151 border-color: currentColor;
a011f1e152 }
a011f1e153 50% {
fe3b509154 border-color: transparent;
a011f1e155 }
a011f1e156}
b2bd123157.badge-running-text-pulse {
fe3b509158 animation: badge-running-border 2s ease-in-out infinite;
fe3b509159}
fe3b509160
bf5fc33161/* ── Focus styles ── */
bf5fc33162*:focus-visible {
bf5fc33163 outline: 2px solid var(--accent);
bf5fc33164 outline-offset: 2px;
bf5fc33165}
bf5fc33166
fe3b509167/* ── Thin scrollbars site-wide ── */
fe3b509168* {
fe3b509169 scrollbar-width: thin;
fe3b509170 scrollbar-color: var(--border) transparent;
fe3b509171}
fe3b509172*::-webkit-scrollbar {
fe3b509173 width: 6px;
fe3b509174 height: 6px;
fe3b509175}
fe3b509176*::-webkit-scrollbar-track {
fe3b509177 background: transparent;
fe3b509178}
fe3b509179*::-webkit-scrollbar-thumb {
fe3b509180 background: var(--border);
fe3b509181 border-radius: 3px;
fe3b509182}
fe3b509183*::-webkit-scrollbar-thumb:hover {
fe3b509184 background: var(--text-faint);
fe3b509185}
fe3b509186
bf5fc33187/* ── Interactive row (file trees, lists) ── */
bf5fc33188.hover-row {
bf5fc33189 transition: background-color 0.1s;
bf5fc33190}
10621c5191@media (hover: hover) {
10621c5192 .hover-row:hover {
10621c5193 background-color: var(--bg-hover);
10621c5194 }
10621c5195}
10621c5196.hover-row:active {
bf5fc33197 background-color: var(--bg-hover);
bf5fc33198}
bf5fc33199
fe3b509200/* ── Log line hover ── */
fe3b509201.log-line:hover {
fe3b509202 background-color: var(--bg-inset);
fe3b509203}
fe3b509204
fe3b509205/* ── Docker group hover ── */
fe3b509206.docker-group-header:hover {
fe3b509207 background-color: var(--bg-inset) !important;
fe3b509208}
fe3b509209.docker-group-header:hover ~ .docker-group-body .log-line {
fe3b509210 background-color: var(--bg-inset);
fe3b509211}
fe3b509212.docker-group-header .docker-group-copy {
fe3b509213 opacity: 0;
fe3b509214}
fe3b509215.docker-group-header:hover .docker-group-copy {
fe3b509216 opacity: 1;
fe3b509217}
fe3b509218
bf5fc33219/* ── Button resets ── */
bf5fc33220.btn-reset {
bf5fc33221 background: none;
bf5fc33222 border: none;
bf5fc33223 cursor: pointer;
bf5fc33224 font: inherit;
bf5fc33225 color: inherit;
bf5fc33226 padding: 0;
bf5fc33227}
bf5fc33228
0b4b582229/* ── Collab presence avatars ── */
0b4b582230.collab-avatar {
0b4b582231 transition: transform 0.15s ease;
0b4b582232}
0b4b582233.collab-avatar:hover {
0b4b582234 transform: scale(1.15);
0b4b582235}
0b4b582236.collab-avatar::after {
0b4b582237 content: attr(data-tooltip);
0b4b582238 position: absolute;
0b4b582239 top: calc(100% + 6px);
0b4b582240 left: 50%;
0b4b582241 transform: translateX(-50%) scale(0.9);
0b4b582242 padding: 3px 8px;
0b4b582243 border-radius: 4px;
0b4b582244 background: var(--bg-inset, #333);
0b4b582245 color: var(--text-primary);
0b4b582246 font-size: 10px;
0b4b582247 font-family: 'JetBrains Mono', Menlo, monospace;
0b4b582248 white-space: nowrap;
0b4b582249 pointer-events: none;
0b4b582250 opacity: 0;
0b4b582251 transition: opacity 0.15s ease, transform 0.15s ease;
0b4b582252 border: 1px solid var(--border);
0b4b582253 z-index: 50;
0b4b582254}
0b4b582255.collab-avatar:hover::after {
0b4b582256 opacity: 1;
0b4b582257 transform: translateX(-50%) scale(1);
0b4b582258}
0b4b582259
bf5fc33260/* ── Markdown prose ── */
bf5fc33261.prose {
bf5fc33262 color: var(--text-secondary);
bf5fc33263 line-height: 1.7;
bf5fc33264}
bf5fc33265.prose h1, .prose h2, .prose h3, .prose h4, .prose h5, .prose h6 {
bf5fc33266 color: var(--text-primary);
bf5fc33267 margin-top: 1.5em;
bf5fc33268 margin-bottom: 0.5em;
bf5fc33269 line-height: 1.3;
bf5fc33270}
bf5fc33271.prose h1 { font-size: 1.5rem; }
bf5fc33272.prose h2 { font-size: 1.25rem; }
bf5fc33273.prose h3 { font-size: 1.1rem; }
bf5fc33274.prose h1:first-child, .prose h2:first-child, .prose h3:first-child {
bf5fc33275 margin-top: 0;
bf5fc33276}
bf5fc33277.prose p {
bf5fc33278 margin: 0.75em 0;
bf5fc33279}
bf5fc33280.prose a {
bf5fc33281 color: var(--accent);
bf5fc33282 text-decoration: underline;
bf5fc33283}
bf5fc33284.prose a:hover {
bf5fc33285 color: var(--accent-hover);
bf5fc33286}
bf5fc33287.prose code {
bf5fc33288 background-color: var(--code-bg);
bf5fc33289 padding: 0.15em 0.35em;
bf5fc33290 font-size: 0.875em;
bf5fc33291}
bf5fc33292.prose pre {
bf5fc33293 background-color: var(--code-bg);
bf5fc33294 padding: 1em;
bf5fc33295 overflow-x: auto;
bf5fc33296 margin: 1em 0;
bf5fc33297 border: 1px solid var(--border-subtle);
bf5fc33298}
bf5fc33299.prose pre code {
bf5fc33300 background: none;
bf5fc33301 padding: 0;
bf5fc33302}
bf5fc33303.prose ul, .prose ol {
bf5fc33304 margin: 0.75em 0;
bf5fc33305 padding-left: 1.5em;
bf5fc33306}
bf5fc33307.prose ul { list-style: disc; }
bf5fc33308.prose ol { list-style: decimal; }
bf5fc33309.prose li { margin: 0.25em 0; }
bf5fc33310.prose blockquote {
bf5fc33311 border-left: 3px solid var(--border);
bf5fc33312 padding-left: 1em;
bf5fc33313 margin: 1em 0;
bf5fc33314 color: var(--text-muted);
bf5fc33315}
bf5fc33316.prose table {
bf5fc33317 width: 100%;
bf5fc33318 border-collapse: collapse;
bf5fc33319 margin: 1em 0;
8a2c7d4320 display: block;
8a2c7d4321 overflow-x: auto;
bf5fc33322}
bf5fc33323.prose th, .prose td {
bf5fc33324 border: 1px solid var(--border-subtle);
bf5fc33325 padding: 0.4em 0.75em;
bf5fc33326 text-align: left;
bf5fc33327}
bf5fc33328.prose th {
bf5fc33329 background-color: var(--bg-card);
bf5fc33330 font-weight: 600;
bf5fc33331}
bf5fc33332.prose img {
bf5fc33333 max-width: 100%;
bf5fc33334}
bf5fc33335.prose hr {
bf5fc33336 border: none;
bf5fc33337 border-top: 1px solid var(--border);
bf5fc33338 margin: 1.5em 0;
bf5fc33339}
bf5fc33340
bf5fc33341/* ── Shiki syntax highlighting (dual theme) ── */
bf5fc33342.shiki,
bf5fc33343.shiki span {
bf5fc33344 color: var(--shiki-light) !important;
bf5fc33345 background-color: transparent !important;
bf5fc33346}
bf5fc33347[data-theme="dark"] .shiki,
bf5fc33348[data-theme="dark"] .shiki span {
bf5fc33349 color: var(--shiki-dark) !important;
bf5fc33350}
4dfd09b351
4dfd09b352/* ── Card hover states ── */
4dfd09b353.card-hover {
4dfd09b354 transition: background-color 0.15s, border-color 0.15s;
4dfd09b355}
4dfd09b356.card-hover:hover {
4dfd09b357 background-color: var(--bg-hover);
4dfd09b358 border-color: var(--border);
4dfd09b359}
4dfd09b360
4dfd09b361/* ── Dialog ── */
ab61b9d362@keyframes dialog-enter {
ab61b9d363 from {
ab61b9d364 opacity: 0;
ab61b9d365 transform: scale(0.96) translateY(8px);
ab61b9d366 }
ab61b9d367 to {
ab61b9d368 opacity: 1;
ab61b9d369 transform: scale(1) translateY(0);
ab61b9d370 }
ab61b9d371}
ab61b9d372@keyframes backdrop-enter {
ab61b9d373 from { opacity: 0; }
ab61b9d374 to { opacity: 1; }
ab61b9d375}
4dfd09b376dialog::backdrop {
4dfd09b377 background-color: rgba(0, 0, 0, 0.4);
ab61b9d378 animation: backdrop-enter 0.15s ease-out;
4dfd09b379}
4dfd09b380[data-theme="dark"] dialog::backdrop {
4dfd09b381 background-color: rgba(0, 0, 0, 0.6);
4dfd09b382}
4dfd09b383dialog {
4dfd09b384 border: none;
4dfd09b385 padding: 0;
4dfd09b386 max-width: calc(100vw - 2rem);
4dfd09b387}
ab61b9d388dialog[open] {
ab61b9d389 animation: dialog-enter 0.2s ease-out;
ab61b9d390}
4dfd09b391
4dfd09b392/* ── Toast entrance ── */
4dfd09b393@keyframes toast-enter {
4dfd09b394 from { opacity: 0; transform: translateY(8px); }
4dfd09b395 to { opacity: 1; transform: translateY(0); }
4dfd09b396}
4dfd09b397.toast-enter {
4dfd09b398 animation: toast-enter 0.15s ease-out;
4dfd09b399}