orchard
mirrorEvery 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
1/* The wipe is a transform, not a left offset.
2
3 Animating left relaid out the sweep on every frame, and the browser scores
4 each of those frames as a layout shift: 0.35 CLS on this page alone. The
5 block is width: 100%, so translateX(-100%) puts it exactly where left: -100%
6 did at every point in the animation. */
7@keyframes about-slideLeft {
8 0% {
9 transform: translateX(-100%);
10 }
11 40% {
12 transform: translateX(0);
13 }
14 60% {
15 transform: translateX(0);
16 }
17 100% {
18 transform: translateX(100%);
19 }
20}
21
22@keyframes about-quickFadeIn {
23 0% {
24 color: rgba(0, 0, 0, 0);
25 }
26 49% {
27 color: rgba(0, 0, 0, 0);
28 }
29 50% {
30 color: rgba(0, 0, 0, 1);
31 }
32 100% {
33 color: rgba(0, 0, 0, 1);
34 }
35}
36
37@keyframes about-fadeIn {
38 0% {
39 color: rgba(0, 0, 0, 0);
40 }
41 100% {
42 color: rgba(0, 0, 0, 1);
43 }
44}
45
46.about-background {
47 position: absolute;
48 top: 0;
49 left: 0;
50 right: 0;
51 bottom: 0;
52 background-color: white;
53 z-index: -2;
54}
55
56.about-words {
57 position: absolute;
58 z-index: -1;
59 top: 0;
60 bottom: 0;
61 left: 60px;
62 right: 0;
63 opacity: 0.05;
64 font-size: 5vh;
65 line-height: 11vh;
66 color: black;
67 text-transform: uppercase;
68 height: 100vh;
69 overflow: hidden;
70}
71
72@media (max-width: 767.98px) {
73 .about-words {
74 top: 50px;
75 font-size: 4vh;
76 line-height: 10vh;
77 left: calc(10px + 5%);
78 }
79}
80
81.about-word {
82 margin: 0;
83 position: absolute;
84 left: 0;
85}
86
87.about-wordText {
88 position: relative;
89 white-space: nowrap;
90 overflow: hidden;
91 color: rgba(0, 0, 0, 0);
92 display: inline-block;
93 vertical-align: top;
94}
95
96.about-wordText::before {
97 content: "";
98 position: absolute;
99 width: 100%;
100 height: 100%;
101 background-color: black;
102 left: 0;
103 transform: translateX(-100%);
104 z-index: 1;
105}
106
107.about-wordAppearActive > .about-wordText,
108.about-wordEnterActive > .about-wordText {
109 animation-name: about-quickFadeIn;
110 animation-duration: 1000ms;
111 animation-fill-mode: forwards;
112}
113
114.about-wordAppearActive > .about-wordText::before,
115.about-wordEnterActive > .about-wordText::before {
116 animation-name: about-slideLeft;
117 animation-duration: 1000ms;
118}
119
120.about-wordExitActive > .about-wordText {
121 animation-name: about-quickFadeIn;
122 animation-duration: 1000ms;
123 animation-direction: reverse;
124}
125
126.about-wordExitActive > .about-wordText::before {
127 animation-name: about-slideLeft;
128 animation-duration: 1000ms;
129 animation-direction: reverse;
130}
131
132.about-wordAppearDone > .about-wordText,
133.about-wordEnterDone > .about-wordText {
134 color: rgba(0, 0, 0, 1);
135}
136
137.about-paragraph {
138 font-size: 1.8em;
139 font-weight: 300;
140 position: relative;
141 color: rgba(0, 0, 0, 0);
142 animation-name: about-fadeIn;
143 animation-delay: 1500ms;
144 animation-duration: 1000ms;
145 animation-fill-mode: forwards;
146}
147
148.about-paragraph::before {
149 content: "";
150 display: block;
151 width: 75px;
152 height: 5px;
153 margin-bottom: 20px;
154 background-color: var(--color-blue);
155}
156
157@media (max-width: 767.98px) {
158 .about-paragraph {
159 font-size: 1.2em;
160 }
161}
162
163.about-strong {
164 font-weight: 700;
165 position: relative;
166 white-space: nowrap;
167 overflow: hidden;
168 animation: about-quickFadeIn 1250ms normal forwards;
169 color: rgba(0, 0, 0, 0);
170 display: inline-block;
171 vertical-align: top;
172}
173
174.about-strong::before {
175 content: "";
176 position: absolute;
177 width: 100%;
178 height: 100%;
179 background-color: black;
180 left: 0;
181 transform: translateX(-100%);
182 z-index: 1;
183 animation: about-slideLeft 1250ms normal forwards;
184}
185
186.about-resume {
187 display: flex;
188 align-items: center;
189 width: fit-content;
190 text-decoration: none;
191 margin-top: 20px;
192 font-weight: 700;
193 color: black;
194 position: relative;
195 overflow: hidden;
196}
197
198.about-resume::before {
199 content: "";
200 display: block;
201 position: absolute;
202 z-index: -1;
203 top: 100%;
204 width: 100%;
205 height: 100%;
206 background: rgba(14, 64, 244, 0.3);
207 transition: top 250ms;
208}
209
210.about-resume:hover::before {
211 top: 60%;
212}
213
214.about-resume svg {
215 margin-right: 10px;
216}