repos
/ orchard main

orchard

mirror

Every site I host, in one repo, along with the Cloudflare Tunnel and Caddy that front them. It's all Go, Vite, and SQLite, and it runs on a desktop at home with nothing listening on an inbound port.

blogbuncaddycloudflare-tunneldockergogolanghomelabhtml-templatemonorepoself-hostedseosqlitestatic-sitetypstuptime-monitoringviteweb-analytics

6.8 KB · 375 lines · CSS Raw History
  1@keyframes art-transformRight {
  2  from {
  3    transform: scaleX(0);
  4  }
  5  to {
  6    transform: scaleX(1);
  7  }
  8}
  9
 10@keyframes art-transformLeft {
 11  from {
 12    transform: scaleX(1);
 13  }
 14  to {
 15    transform: scaleX(0);
 16  }
 17}
 18
 19@keyframes art-lightboxFadeIn {
 20  from {
 21    opacity: 0;
 22  }
 23  to {
 24    opacity: 1;
 25  }
 26}
 27
 28@keyframes art-lightboxScaleIn {
 29  from {
 30    opacity: 0;
 31    transform: scale(0.92);
 32  }
 33  to {
 34    opacity: 1;
 35    transform: scale(1);
 36  }
 37}
 38
 39@keyframes art-lightboxPulse {
 40  0%, 100% {
 41    opacity: 0.4;
 42  }
 43  50% {
 44    opacity: 1;
 45  }
 46}
 47
 48.art-background {
 49  position: absolute;
 50  top: 0;
 51  left: 0;
 52  right: 0;
 53  bottom: 0;
 54  background-color: white;
 55  z-index: -2;
 56}
 57
 58.art-heading {
 59  font-weight: 700;
 60  margin-top: 60px;
 61  margin-bottom: 10px;
 62  font-size: 2.5em;
 63  color: black;
 64}
 65
 66.art-heading::before {
 67  content: "";
 68  display: block;
 69  width: 50px;
 70  height: 5px;
 71  margin-bottom: 20px;
 72  background-image: linear-gradient(
 73    to right,
 74    var(--color-blue) 0,
 75    var(--color-purple) 100%
 76  );
 77}
 78
 79.art-paragraph {
 80  font-size: 1.3em;
 81  margin-top: 0;
 82  margin-bottom: 24px;
 83  font-weight: 300;
 84  color: rgba(0, 0, 0, 0.7);
 85  line-height: 1.6;
 86}
 87
 88.art-subheading {
 89  font-weight: 700;
 90  margin-top: 48px;
 91  margin-bottom: 12px;
 92  font-size: 1.6em;
 93  color: black;
 94  display: flex;
 95  align-items: center;
 96  gap: 12px;
 97}
 98
 99.art-subheading > span {
100  font-family: monospace;
101  font-size: 0.7em;
102  padding: 2px 8px;
103  background-image: linear-gradient(
104    to right,
105    var(--color-blue) 0,
106    var(--color-purple) 100%
107  );
108  color: white;
109  border-radius: var(--radius-2);
110  letter-spacing: 1px;
111}
112
113.art-paragraph a {
114  color: black;
115  text-decoration: none;
116  position: relative;
117  white-space: nowrap;
118}
119
120.art-paragraph a::before {
121  content: "";
122  position: absolute;
123  left: 0;
124  right: 0;
125  bottom: 0;
126  height: 2px;
127  background: rgba(0, 0, 0, 1);
128  transform-origin: left;
129  animation: art-transformLeft 300ms normal forwards;
130}
131
132.art-paragraph a::after {
133  content: "";
134  position: absolute;
135  left: 0;
136  right: 0;
137  bottom: 0;
138  height: 2px;
139  background: rgba(0, 0, 0, 0.2);
140}
141
142.art-paragraph a:hover::before {
143  animation: art-transformRight 300ms normal forwards;
144}
145
146.art-artGrid {
147  display: grid;
148  grid-template-columns: repeat(2, 1fr);
149  gap: 16px;
150}
151
152@media (max-width: 767.98px) {
153  .art-artGrid {
154    grid-template-columns: 1fr;
155  }
156}
157
158.art-artItem {
159  position: relative;
160  overflow: hidden;
161  border-radius: var(--radius-2);
162  transition: transform 300ms, box-shadow 300ms;
163}
164
165.art-artItem:hover {
166  transform: translateY(-3px);
167  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3);
168}
169
170.art-cardImage {
171  display: block;
172  background-color: var(--color-primary);
173  aspect-ratio: 16 / 9;
174  overflow: hidden;
175}
176
177.art-cardImage img {
178  object-fit: cover;
179  object-position: center;
180  width: 100%;
181  height: auto;
182  aspect-ratio: 16 / 9;
183  display: block;
184  transition: opacity 400ms ease-out;
185}
186
187/* Gated on data-js for the same reason as .index-hero: initCardFades reveals
188   these, so ungated a JS failure renders seven blank boxes where the artwork is. */
189html[data-js] .art-cardImage img {
190  opacity: 0;
191}
192
193/* Matches the specificity of the data-js gate above, which would otherwise
194   outrank this and leave every card stuck at opacity 0. */
195html[data-js] .art-cardImage img.art-imgLoaded {
196  opacity: 1;
197}
198
199.art-artItemHeader {
200  margin: 0;
201  padding: 10px 14px;
202  display: flex;
203  justify-content: space-between;
204  align-items: center;
205  font-weight: 700;
206  font-size: 0.95em;
207  background: black;
208  color: white;
209}
210
211.art-artItemHeader > span {
212  font-family: monospace;
213  font-weight: 400;
214  font-size: 1em;
215  color: rgba(255, 255, 255, 0.8);
216  letter-spacing: 1px;
217}
218
219.art-artItemButton {
220  padding: 8px 14px;
221  font-size: 0.9em;
222  text-decoration: none;
223  font-weight: 700;
224  text-transform: uppercase;
225  display: inline-block;
226  letter-spacing: 2px;
227  color: white;
228  background-image: linear-gradient(
229    to right,
230    var(--color-blue) 0,
231    var(--color-purple) 100%
232  );
233  border-radius: var(--radius-2);
234  transform: scale(1);
235  transition: transform 250ms;
236  margin-bottom: 20px;
237}
238
239.art-artItemButton:hover {
240  transform: scale(1.1);
241}
242
243.art-artContainer {
244  width: 100%;
245  height: 500px;
246  max-height: 100vh;
247  background: black;
248  margin-bottom: 16px;
249  position: relative;
250  overflow: hidden;
251  border-radius: var(--radius-2);
252}
253
254.art-playButton {
255  position: absolute;
256  top: 16px;
257  right: 16px;
258  width: 44px;
259  height: 44px;
260  border: 1px solid rgba(255, 255, 255, 0.2);
261  border-radius: var(--radius-2);
262  background: rgba(0, 0, 0, 0.5);
263  color: white;
264  font-size: 20px;
265  line-height: 1;
266  padding: 0;
267  cursor: pointer;
268  display: flex;
269  align-items: center;
270  justify-content: center;
271  transition: border-color 200ms, background 200ms;
272  z-index: 5;
273}
274
275.art-playButton:hover {
276  border-color: var(--color-blue);
277  background: rgba(14, 63, 244, 0.2);
278}
279
280.art-playButton:active {
281  transform: scale(0.95);
282}
283
284/* Lightbox */
285
286/* The hidden attribute sets display:none from the UA stylesheet, which any
287   author display rule outranks. Without this the lightbox is open on arrival.
288   The React version had no equivalent because it rendered the portal only
289   while an image was selected, so there was nothing to hide. */
290.art-lightboxOverlay[hidden] {
291  display: none;
292}
293
294.art-lightboxOverlay {
295  position: fixed;
296  top: 0;
297  left: 0;
298  right: 0;
299  bottom: 0;
300  background: rgba(0, 0, 0, 0.92);
301  display: flex;
302  align-items: center;
303  justify-content: center;
304  z-index: 99999;
305  animation: art-lightboxFadeIn 300ms ease-out;
306}
307
308.art-lightboxImageWrapper {
309  position: relative;
310  width: 90vw;
311  height: 90vh;
312  animation: art-lightboxScaleIn 400ms cubic-bezier(0.16, 1, 0.3, 1);
313  background: black;
314  border-radius: var(--radius-2);
315  overflow: hidden;
316}
317
318.art-lightboxImage {
319  /* next/image fill mode supplied the absolute positioning inline. */
320  position: absolute;
321  inset: 0;
322  width: 100%;
323  height: 100%;
324  object-fit: contain;
325  visibility: hidden;
326  opacity: 0;
327  transition: opacity 300ms ease-out;
328}
329
330.art-lightboxLoading {
331  position: absolute;
332  top: 50%;
333  left: 50%;
334  transform: translate(-50%, -50%);
335  color: var(--color-blue);
336  font-family: monospace;
337  font-size: 1.2em;
338  letter-spacing: 4px;
339  text-transform: uppercase;
340  animation: art-lightboxPulse 1.5s ease-in-out infinite;
341}
342
343.art-show {
344  opacity: 1;
345  visibility: visible;
346}
347
348.art-hide {
349  opacity: 0;
350  visibility: hidden;
351}
352
353.art-lightboxClose {
354  position: absolute;
355  top: 16px;
356  right: 16px;
357  width: 40px;
358  height: 40px;
359  background: rgba(0, 0, 0, 0.6);
360  border: 1px solid rgba(255, 255, 255, 0.2);
361  border-radius: var(--radius-2);
362  color: white;
363  font-size: 1.2em;
364  display: flex;
365  align-items: center;
366  justify-content: center;
367  transition: border-color 200ms, background 200ms;
368  z-index: 1;
369}
370
371.art-lightboxClose:hover {
372  border-color: var(--color-blue);
373  background: rgba(14, 63, 244, 0.2);
374}