497 lines
9.7 KiB
CSS
497 lines
9.7 KiB
CSS
/* ---------------------------------------------------------------------------
|
||
nak0x.dev — a terminal-shaped sheet of paper.
|
||
Everything is monospace, everything sits on a 1px ink rule.
|
||
--------------------------------------------------------------------------- */
|
||
|
||
:root,
|
||
:root[data-theme='light'] {
|
||
--paper: #f6f3ec;
|
||
--paper-soft: #efece4;
|
||
--ink: #0a0a0a;
|
||
--ink-mute: #4a4a4a;
|
||
--ink-faint: #8a8a8a;
|
||
--rule: #0a0a0a;
|
||
--accent: #D97629;
|
||
}
|
||
|
||
:root[data-theme='dark'] {
|
||
--paper: #0e0e10;
|
||
--paper-soft: #16161a;
|
||
--ink: #ece9e0;
|
||
--ink-mute: #9a9a9a;
|
||
--ink-faint: #6a6a6a;
|
||
--rule: #ece9e0;
|
||
--accent: #D97629;
|
||
}
|
||
|
||
@media (prefers-color-scheme: dark) {
|
||
:root:not([data-theme]) {
|
||
--paper: #0e0e10;
|
||
--paper-soft: #16161a;
|
||
--ink: #ece9e0;
|
||
--ink-mute: #9a9a9a;
|
||
--ink-faint: #6a6a6a;
|
||
--rule: #ece9e0;
|
||
--accent: #e56fd8;
|
||
}
|
||
}
|
||
|
||
* {
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
html,
|
||
body {
|
||
margin: 0;
|
||
padding: 0;
|
||
background: var(--paper);
|
||
color: var(--ink);
|
||
}
|
||
|
||
html {
|
||
font-family: 'JetBrains Mono', ui-monospace, 'IBM Plex Mono', Menlo, Monaco,
|
||
'Liberation Mono', 'DejaVu Sans Mono', Consolas, monospace;
|
||
font-size: 15px;
|
||
line-height: 1.55;
|
||
-webkit-font-smoothing: antialiased;
|
||
-moz-osx-font-smoothing: grayscale;
|
||
}
|
||
|
||
body {
|
||
min-height: 100vh;
|
||
}
|
||
|
||
::selection {
|
||
background: var(--ink);
|
||
color: var(--paper);
|
||
}
|
||
|
||
h1,
|
||
h2,
|
||
h3,
|
||
h4 {
|
||
font-weight: 600;
|
||
margin: 0;
|
||
letter-spacing: -0.01em;
|
||
}
|
||
h1 { font-size: 1.5rem; }
|
||
h2 { font-size: 1.05rem; text-transform: lowercase; }
|
||
h3 { font-size: 0.95rem; text-transform: lowercase; color: var(--ink-mute); }
|
||
p { margin: 0; }
|
||
|
||
a {
|
||
color: var(--ink);
|
||
text-decoration: underline;
|
||
text-decoration-thickness: 1px;
|
||
text-underline-offset: 3px;
|
||
}
|
||
a:hover {
|
||
background: var(--accent);
|
||
color: var(--paper);
|
||
text-decoration: none;
|
||
}
|
||
|
||
hr {
|
||
border: 0;
|
||
border-top: 1px solid var(--rule);
|
||
margin: 1rem 0;
|
||
}
|
||
|
||
pre { margin: 0; font-family: inherit; }
|
||
|
||
/* --- layout --------------------------------------------------------------- */
|
||
|
||
.paper {
|
||
max-width: 1080px;
|
||
margin: 0 auto;
|
||
padding: 2.5rem 1.25rem 6rem;
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
.stack > * + * { margin-top: 1.25rem; }
|
||
.stack-sm > * + * { margin-top: 0.5rem; }
|
||
|
||
.row {
|
||
display: flex;
|
||
gap: 1rem;
|
||
align-items: baseline;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.column { display: grid; gap: 1.25rem; }
|
||
|
||
.grid-2 {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 1.25rem;
|
||
}
|
||
@media (max-width: 700px) {
|
||
.grid-2 { grid-template-columns: 1fr; }
|
||
}
|
||
|
||
/* --- the frame: a 1px box with `+` corners, like a TUI widget -------------- */
|
||
|
||
.frame {
|
||
position: relative;
|
||
border: 1px solid var(--ink);
|
||
background: var(--paper);
|
||
padding: 1rem 1.25rem;
|
||
}
|
||
.frame::before,
|
||
.frame::after {
|
||
content: '+';
|
||
position: absolute;
|
||
width: 12px;
|
||
height: 12px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
line-height: 1;
|
||
background: var(--paper);
|
||
color: var(--ink);
|
||
font-size: 0.95rem;
|
||
z-index: 2;
|
||
pointer-events: none;
|
||
}
|
||
.frame::before { top: -6px; left: -6px; }
|
||
.frame::after { bottom: -6px; right: -6px; }
|
||
|
||
.frame-tag {
|
||
position: absolute;
|
||
top: -0.6rem;
|
||
left: 0.75rem;
|
||
background: var(--paper);
|
||
padding: 0 0.4rem;
|
||
font-size: 0.75rem;
|
||
text-transform: lowercase;
|
||
letter-spacing: 0.04em;
|
||
color: var(--ink-mute);
|
||
z-index: 2;
|
||
}
|
||
|
||
.accent-on-hover:hover {
|
||
/* the box is often an <a>, so undo the global link-hover fill */
|
||
background: var(--paper);
|
||
border-color: var(--accent);
|
||
}
|
||
.accent-on-hover:hover::before,
|
||
.accent-on-hover:hover::after {
|
||
color: var(--accent);
|
||
}
|
||
|
||
/* --- text helpers --------------------------------------------------------- */
|
||
|
||
.muted { color: var(--ink-mute); }
|
||
.faint { color: var(--ink-faint); }
|
||
.small { font-size: 0.85rem; }
|
||
.tiny { font-size: 0.75rem; letter-spacing: 0.04em; text-transform: uppercase; }
|
||
.accent { color: var(--accent); }
|
||
.lower { text-transform: lowercase; }
|
||
.nowrap { white-space: nowrap; }
|
||
|
||
.ascii-rule {
|
||
color: var(--ink-faint);
|
||
white-space: pre;
|
||
overflow: hidden;
|
||
user-select: none;
|
||
line-height: 1;
|
||
}
|
||
|
||
/* --- lists ---------------------------------------------------------------- */
|
||
|
||
.bullets {
|
||
list-style: none;
|
||
padding: 0;
|
||
margin: 0.85rem 0 0;
|
||
color: var(--ink-mute);
|
||
font-size: 0.92rem;
|
||
}
|
||
.bullets li {
|
||
padding-left: 1.25rem;
|
||
position: relative;
|
||
}
|
||
.bullets li::before {
|
||
content: '\203A';
|
||
position: absolute;
|
||
left: 0;
|
||
color: var(--accent);
|
||
}
|
||
|
||
.def-list {
|
||
margin: 0;
|
||
display: grid;
|
||
grid-template-columns: max-content 1fr;
|
||
column-gap: 1rem;
|
||
row-gap: 0.35rem;
|
||
font-size: 0.9rem;
|
||
line-height: 1.5;
|
||
}
|
||
.def-list dt {
|
||
color: var(--ink-mute);
|
||
text-transform: lowercase;
|
||
letter-spacing: 0.04em;
|
||
white-space: nowrap;
|
||
}
|
||
.def-list dd {
|
||
margin: 0;
|
||
min-width: 0;
|
||
position: relative;
|
||
padding-left: 1rem;
|
||
}
|
||
.def-list dd::before {
|
||
content: '\203A';
|
||
position: absolute;
|
||
left: 0;
|
||
color: var(--accent);
|
||
}
|
||
@media (max-width: 480px) {
|
||
.def-list { grid-template-columns: 1fr; row-gap: 0.15rem; }
|
||
.def-list dt { margin-top: 0.4rem; }
|
||
.def-list dt:first-of-type { margin-top: 0; }
|
||
}
|
||
|
||
/* --- rendered markdown ---------------------------------------------------- */
|
||
|
||
.prose { font-size: 0.95rem; }
|
||
.prose > * + * { margin-top: 1rem; }
|
||
.prose h2,
|
||
.prose h3,
|
||
.prose h4 {
|
||
margin-top: 2rem;
|
||
text-transform: none;
|
||
color: var(--ink);
|
||
scroll-margin-top: 2rem;
|
||
}
|
||
.prose h2 { font-size: 1.15rem; }
|
||
.prose h2::before,
|
||
.prose h3::before {
|
||
content: '# ';
|
||
color: var(--accent);
|
||
}
|
||
.prose h3 { font-size: 1rem; }
|
||
.prose ul,
|
||
.prose ol { padding-left: 1.5rem; margin-top: 0.75rem; }
|
||
.prose li + li { margin-top: 0.25rem; }
|
||
.prose li::marker { color: var(--accent); }
|
||
.prose img {
|
||
display: block;
|
||
max-width: 100%;
|
||
height: auto;
|
||
border: 1px solid var(--ink);
|
||
}
|
||
.prose blockquote {
|
||
margin: 0;
|
||
border-left: 2px solid var(--accent);
|
||
padding-left: 1rem;
|
||
color: var(--ink-mute);
|
||
}
|
||
.prose code {
|
||
background: var(--paper-soft);
|
||
border: 1px solid var(--paper-soft);
|
||
padding: 0.05em 0.35em;
|
||
font-size: 0.9em;
|
||
}
|
||
.prose pre {
|
||
border: 1px solid var(--ink);
|
||
padding: 1rem;
|
||
overflow-x: auto;
|
||
background: var(--paper-soft) !important;
|
||
font-size: 0.85rem;
|
||
line-height: 1.5;
|
||
}
|
||
.prose pre code {
|
||
background: none;
|
||
border: 0;
|
||
padding: 0;
|
||
font-size: inherit;
|
||
}
|
||
.prose table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
font-size: 0.88rem;
|
||
display: block;
|
||
overflow-x: auto;
|
||
}
|
||
.prose th,
|
||
.prose td {
|
||
border: 1px solid var(--ink-faint);
|
||
padding: 0.35rem 0.6rem;
|
||
text-align: left;
|
||
}
|
||
.prose .heading-anchor {
|
||
text-decoration: none;
|
||
color: var(--ink-faint);
|
||
opacity: 0;
|
||
padding-left: 0.4rem;
|
||
}
|
||
.prose :is(h2, h3, h4):hover .heading-anchor { opacity: 1; }
|
||
|
||
/* shiki emits both themes; swap them with the css variable trick */
|
||
html[data-theme='dark'] .shiki,
|
||
html[data-theme='dark'] .shiki span {
|
||
color: var(--shiki-dark) !important;
|
||
background-color: transparent !important;
|
||
font-style: var(--shiki-dark-font-style) !important;
|
||
}
|
||
@media (prefers-color-scheme: dark) {
|
||
html:not([data-theme]) .shiki,
|
||
html:not([data-theme]) .shiki span {
|
||
color: var(--shiki-dark) !important;
|
||
background-color: transparent !important;
|
||
}
|
||
}
|
||
|
||
/* --- forms & buttons ------------------------------------------------------
|
||
Used by /dash. Same rules as the rest of the page: 1px ink, no radius,
|
||
monospace, inversion on interaction.
|
||
--------------------------------------------------------------------------- */
|
||
|
||
.field {
|
||
display: block;
|
||
}
|
||
|
||
.field > .label {
|
||
display: block;
|
||
font-size: 0.75rem;
|
||
letter-spacing: 0.04em;
|
||
text-transform: lowercase;
|
||
color: var(--ink-mute);
|
||
margin-bottom: 0.25rem;
|
||
}
|
||
|
||
.input,
|
||
.textarea,
|
||
.select {
|
||
width: 100%;
|
||
font: inherit;
|
||
font-size: 0.9rem;
|
||
color: var(--ink);
|
||
background: var(--paper-soft);
|
||
border: 1px solid var(--ink-faint);
|
||
padding: 0.35rem 0.5rem;
|
||
border-radius: 0;
|
||
-webkit-appearance: none;
|
||
appearance: none;
|
||
}
|
||
|
||
.input:focus,
|
||
.textarea:focus,
|
||
.select:focus {
|
||
outline: none;
|
||
border-color: var(--accent);
|
||
box-shadow: inset 0 0 0 1px var(--accent);
|
||
}
|
||
|
||
.textarea {
|
||
resize: vertical;
|
||
line-height: 1.55;
|
||
tab-size: 2;
|
||
}
|
||
|
||
.select {
|
||
/* room for the caret we draw with the wrapper */
|
||
padding-right: 1.5rem;
|
||
}
|
||
|
||
.checkbox {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.45rem;
|
||
font-size: 0.85rem;
|
||
cursor: pointer;
|
||
user-select: none;
|
||
}
|
||
|
||
.checkbox input {
|
||
appearance: none;
|
||
width: 1rem;
|
||
height: 1rem;
|
||
border: 1px solid var(--ink-faint);
|
||
background: var(--paper-soft);
|
||
display: grid;
|
||
place-content: center;
|
||
cursor: pointer;
|
||
margin: 0;
|
||
}
|
||
|
||
.checkbox input:checked {
|
||
border-color: var(--accent);
|
||
}
|
||
|
||
.checkbox input:checked::after {
|
||
content: '×';
|
||
color: var(--accent);
|
||
font-size: 0.9rem;
|
||
line-height: 1;
|
||
}
|
||
|
||
.btn {
|
||
font: inherit;
|
||
font-size: 0.85rem;
|
||
color: var(--ink);
|
||
background: var(--paper);
|
||
border: 1px solid var(--ink);
|
||
padding: 0.3rem 0.75rem;
|
||
cursor: pointer;
|
||
text-decoration: none;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.4rem;
|
||
white-space: nowrap;
|
||
border-radius: 0;
|
||
}
|
||
|
||
.btn:hover:not(:disabled) {
|
||
background: var(--ink);
|
||
color: var(--paper);
|
||
}
|
||
|
||
.btn:disabled {
|
||
opacity: 0.45;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
.btn-primary {
|
||
border-color: var(--accent);
|
||
color: var(--accent);
|
||
}
|
||
|
||
.btn-primary:hover:not(:disabled) {
|
||
background: var(--accent);
|
||
color: var(--paper);
|
||
}
|
||
|
||
.btn-danger:hover:not(:disabled) {
|
||
background: #c0392b;
|
||
border-color: #c0392b;
|
||
color: #fff;
|
||
}
|
||
|
||
.btn-ghost {
|
||
border-color: transparent;
|
||
padding-inline: 0.35rem;
|
||
}
|
||
|
||
.btn-ghost:hover:not(:disabled) {
|
||
background: var(--ink);
|
||
color: var(--paper);
|
||
}
|
||
|
||
/* inline status line: ok / working / failed */
|
||
.flash {
|
||
font-size: 0.8rem;
|
||
padding: 0.35rem 0.6rem;
|
||
border: 1px solid var(--ink-faint);
|
||
}
|
||
|
||
.flash-ok {
|
||
border-color: var(--accent);
|
||
color: var(--accent);
|
||
}
|
||
|
||
.flash-error {
|
||
border-color: #c0392b;
|
||
color: #c0392b;
|
||
}
|