@charset "utf-8" ;
/* ****************************** */
/* RESETS */
* {
box-sizing : border-box ;
margin-block : initial ;
}
body {
margin : initial ;
padding : initial ;
}
img {
display : block ;
max-width : 100 % ;
height : auto ;
}
figure {
margin-inline : initial ;
}
blockquote {
margin-inline : initial ;
}
pre {
tab-size : 4 ;
}
button {
cursor : pointer ;
}
/* ****************************** */
/* TYPOGRAPHY */
@font-face {
font-family : "Switzer Variable" ;
src : local ( "Switzer Variable" ),
url ( "/fonts/Switzer-Variable.woff2" ) format ( "woff2" );
font-weight : 100 900 ;
font-display : swap ;
}
@font-face {
font-family : "Switzer Variable" ;
src : local ( "Switzer Variable Italic" ),
url ( "/fonts/Switzer-VariableItalic.woff2" ) format ( "woff2" );
font-weight : 100 900 ;
font-style : italic ;
font-display : swap ;
}
@font-face {
font-family : "Source Serif 4" ;
src : local ( "Source Serif 4" ),
url ( "/fonts/SourceSerif4-VariableFont_opsz,wght.woff2" ) format ( "woff2" );
font-display : swap ;
}
@font-face {
font-family : "iA Writer Quattro V" ;
src : local ( "iA Writer Quattro V" ),
url ( "/fonts/iAWriterQuattroV.woff2" ) format ( "woff2" );
font-display : swap ;
}
:root {
/* Base font */
--font-stack-sans-serif : "Switzer Variable" , system-ui , sans-serif ;
--font-stack-serif : "Source Serif 4" , Georgia , Times , serif ;
--font-stack-code : "iA Writer Quattro V" , Menlo, monospace ;
font-size : 1.0625 em ;
font-family : var ( --font-stack-sans-serif );
--font-weight-light-mode : 350 ;
--font-weight-dark-mode : 250 ;
font-weight : var ( --font-weight-light-mode );
transition : font-weight var ( --theme-transition-duration ) ease-out ;
/* ***** Vertical rhythm ***** */
--root-line-height : 1.5 ;
line-height : var ( --root-line-height );
/* Block spacing factor. If used, this should be in increments of 0.5 to
maintain rhythm */
--flow-space-multiplier : 0.5 ;
--flow-space : calc ( var ( --flow-space-multiplier ) * 1 rlh );
/* Type scale */
-webkit-text-size-adjust : none ;
text-size-adjust : none ;
/* Set up size ratios as raw, unitless numbers */
--size-ratio : 1.3 ;
--size-1 : 1 ;
--size-2 : calc ( var ( --size-1 ) * var ( --size-ratio ));
--size-3 : calc ( var ( --size-2 ) * var ( --size-ratio ));
--size-4 : calc ( var ( --size-3 ) * var ( --size-ratio ));
--size-5 : calc ( var ( --size-4 ) * var ( --size-ratio ));
/* Assign units for usage */
--size-1-rem : calc ( var ( --size-1 ) * 1 rem );
--size-2-rem : calc ( var ( --size-2 ) * 1 rem );
--size-3-rem : calc ( var ( --size-3 ) * 1 rem );
--size-4-rem : calc ( var ( --size-4 ) * 1 rem );
--size-5-rem : calc ( var ( --size-5 ) * 1 rem );
/* Fit headings into our rlh baseline grid.
The line-height for our headings should be the minimum number of
baseline grid units that their font-size fits into.
- Calculate how many baseline grid units a given font size fits into
- Round up to the nearest whole baseline grid unit
- Apply units (rlh) to the final value for usage
NOTE: This idiosyncrasy with calc() has bitten me before. Via MDN:
> Current implementations require that, when using the * and /
operators, one of the operands must be unitless. For /, the right
operand must be unitless. For example font-size: calc(1.25rem / 1.25)
is valid but font-size: calc(1.25rem / 125%) is invalid.
So for simplicity with calculations involving the baseline grid, work
exclusively with raw numbers until the final step, and apply length
units at the end.
*/
--size-1-rlh : calc (
round (
up,
/* font-size into line-height */
calc ( var ( --size-1 ) / var ( --root-line-height )),
/* Round up to nearest whole baseline grid unit */
var ( --flow-space-multiplier )
/* Apply length units to final value */
) * 1 rlh
);
--size-2-rlh : calc (
round (
up,
calc ( var ( --size-2 ) / var ( --root-line-height )),
var ( --flow-space-multiplier )
) * 1 rlh
);
--size-3-rlh : calc (
round (
up,
calc ( var ( --size-3 ) / var ( --root-line-height )),
var ( --flow-space-multiplier )
) * 1 rlh
);
--size-4-rlh : calc (
round (
up,
calc ( var ( --size-4 ) / var ( --root-line-height )),
var ( --flow-space-multiplier )
) * 1 rlh
);
--size-5-rlh : calc (
round (
up,
calc ( var ( --size-5 ) / var ( --root-line-height )),
var ( --flow-space-multiplier )
) * 1 rlh
);
/* Ensure that gutters leave enough space for outside bullets */
--inline-gutter : 2 rem ;
/* Set a readable line length, accounting for gutter (padding) with
box-sizing border-box. Note that Firefox doesn't currently (250830)
support rch units. */
--wrap-width : calc ( var ( --inline-gutter ) * 2 + 72 ch );
}
h1 ,
h2 ,
h3 ,
h4 ,
h5 ,
h6 {
/* <3 but not licensed for web use 😔 */
/* font-family: "Hiragino Mincho ProN"; */
/* font-weight: 600; */
font-family : var ( --font-stack-serif );
font-feature-settings : "onum" ;
font-weight : 500 ;
/* Ensure headings have their spacing, even when they're the first item in
a flow section (.flow > * + *)
*/
margin-block-start : var ( --flow-space , 1 em );
}
:root [ data-theme = "dark" ] :is ( h1 , h2 , h3 , h4 , h5 , h6 ) {
font-weight : 450 ;
}
h1 {
font-size : var ( --size-4-rem , 2 rem );
line-height : var ( --size-4-rlh );
--flow-space : 0 ;
}
h2 {
font-size : var ( --size-3-rem , 1.5 rem );
line-height : var ( --size-3-rlh );
--flow-space : 3 rlh ;
}
h3 {
font-size : var ( --size-2-rem , 1.25 rem );
line-height : var ( --size-2-rlh );
--flow-space : 2 rlh ;
}
h4 {
font-size : var ( --size-1-rem , 1 rem );
line-height : var ( --size-1-rlh );
--flow-space : 0 ;
}
ul ,
ol {
padding-inline-start : 0 ;
list-style-position : outside ; /* Default, but being explicit */
}
li > :is ( ul , ol , dl ) {
padding-inline-start : var ( --inline-gutter , 2 em );
}
b ,
strong {
font-weight : 550 ;
transition : font-weight var ( --theme-transition-duration ) ease-out ;
}
:root [ data-theme = "dark" ] :is ( b , strong ) {
font-weight : 500 ;
}
button {
font-size : 0.875 rem ;
padding : 0.25 em ;
}
code {
font-family : var ( --font-family-code );
font-weight : 400 ;
}
figcaption {
padding-inline : var ( --inline-gutter , 2 em );
}
blockquote {
font-style : italic ;
/* Italicized block text reads better in standard weight, even in dark
mode */
/* font-weight: var(--font-weight-light-mode); */
font-weight : calc ( var ( --font-weight-dark-mode ) + 50 );
}
main {
margin-block : 3 rlh ;
}
@media print {
:root {
font-size : 0.875 em ;
--wrap-width : 80 ch ;
}
/* Reduce vertical space between sections */
h2 {
--flow-space : 2 rlh ;
}
h3 {
--flow-space : 1 rlh ;
}
}
/* ****************************** */
/* COLOR AND THEME */
:root {
/* Primitive colors */
--color-soft-pure-white : oklch ( 97.6 % 0 89.9 );
--color-soft-pure-black : oklch ( 14.9 % 0 69.8 );
--color-dark-blue : oklch ( 36.8 % 0.0965 258.5 );
--color-midnight-blue : oklch ( 31.9 % 0.0509 258.7 );
--color-light-blue : oklch ( 89.9 % 0.0186 250.6 );
--color-bone-oatmeal-1 : oklch ( 97.6 % 0.0232 90.8 );
--color-bone-oatmeal-2 : oklch ( 98.5 % 0.0159 88.4 );
--color-tawny-rust-dark : oklch ( 61.8 % 0.1797 44 );
--color-tawny-rust-light : oklch ( 70.8 % 0.197 46.7 );
/* Semantic colors */
/* TODO: Try to use semantic variables everywhere outside of this selector.
Search --color and see how many special use cases we're dealing
with. We may have to compromise to avoid creating too many one-off
semantic variables. */
/* TODO: Make sure we're using the colors consistently (e.g. are we mixing
the two bone colors incorrectly?) */
--color-bg : var ( --color-soft-pure-white );
--color-fg : var ( --color-soft-pure-black );
--color-background : light-dark( var ( --color-bone-oatmeal-2 ), var ( --color-midnight-blue ));
--color-base-text : light-dark( var ( --color-fg ), var ( --color-bone-oatmeal-1 ));
--color-links-buttons : light-dark(
var ( --color-dark-blue , inherit ),
var ( --color-light-blue , inherit )
);
--color-accent : light-dark( var ( --color-tawny-rust-dark ), var ( --color-tawny-rust-light ));
--color-selection-fg : light-dark( var ( --color-dark-blue ), var ( --color-light-blue ));
--color-selection-bg : light-dark( var ( --color-tawny-rust-light ), var ( --color-tawny-rust-dark ));
/* Enable dark mode switching */
color-scheme : light dark ;
--theme-transition-duration : 500 ms ;
}
/* Enable explicit light-dark toggle */
:root [ data-theme = "light" ] {
color-scheme : light ;
font-weight : var ( --font-weight-light-mode );
}
:root [ data-theme = "dark" ] {
color-scheme : dark ;
font-weight : var ( --font-weight-dark-mode );
/* Letter spacing also helps dark mode readability but disables
ligatures */
/* letter-spacing: 0.0015em; */
}
body {
background-color : var ( --color-background );
color : var ( --color-base-text );
transition-property : color , background-color;
transition-duration : var ( --theme-transition-duration );
transition-timing-function : ease-out ;
}
:any-link {
color : var ( --color-links-buttons , initial );
text-decoration-color : currentColor ;
text-decoration-thickness : 0.05 em ;
text-underline-offset : 0.08 em ;
}
:any-link:hover {
text-decoration-color : var ( --color-accent );
text-decoration-thickness : 0.08 em ;
text-underline-offset : 0.09 em ;
}
::marker {
color : light-dark(
var ( --color-fg , hsl ( 0 0 % 20 % )),
var ( --color-bg , hsl ( 0 0 % 85 % ))
);
transition : color var ( --theme-transition-duration ) ease-out ;
}
::selection {
color : var ( --color-selection-fg );
background-color : var ( --color-selection-bg );
}
button {
color : var ( --color-base-text );
border : 1 px solid var ( --color-base-text );
border-radius : 0.5 em ;
}
@media print {
/* Undo *all* dark mode changes. The print media query only changes
light-dark() colors to light - it doesn't affect anything else we've
changed for dark mode.
`color-scheme: light` handles resetting all the color variables, which
will not only set text to light mode, but i.e. the svg logo as well.
Note we don't have to reset the toggle button because it's hidden for
print.
*/
:root [ data-theme = "dark" ] {
color-scheme : light ;
font-weight : 350 ;
}
:root [ data-theme = "dark" ] :is ( b , strong ) {
font-weight : 550 ;
}
:root [ data-theme = "dark" ] :is ( h1 , h2 , h3 , h4 , h5 , h6 ) {
font-weight : 500 ;
}
/* Render link urls in markdown syntax when printing */
/* ...we can, but do we want to? Some of the links are long. */
/*
:any-link::before {
content: "[";
}
:any-link::after {
content: "](" attr(href) ")";
}
*/
}
/* ****************************** */
/* UTILITIES */
.wrapper {
max-width : var ( --wrap-width );
padding-inline : var ( --inline-gutter , 2 rem );
margin-inline : auto ;
}
@media print {
/* Reduce margin; there will already be print margins */
.wrapper {
max-width : 100 % ;
margin-block : var ( --flow-space );
}
}
.flow > * + * {
margin-block-start : var ( --flow-space , 1 em );
}
.text-align-start {
text-align : start ;
}
.text-align-center {
text-align : center ;
}
.text-align-end {
text-align : end ;
}
.text-serif {
font-family : var ( --font-stack-serif );
font-feature-settings : "onum" ;
}
.text-sans {
font-family : var ( --font-stack-sans-serif );
/* font-feature-settings: "onum"; */
}
/* ****************************** */
/* COMPONENT: Site Nav */
.site-nav {
display : flex ;
flex-flow : row wrap ;
justify-content : end ;
align-items : center ;
gap : 0.5 rlh ;
padding-block : 0.2 rlh ;
padding-inline : 1 rlh ;
position : sticky ;
top : 0 ;
color : var ( --color-links-buttons );
background-color : var ( --color-background );
/* background-image: linear-gradient(
135deg,
var(--color-background) 0rlh, 0.5rlh,
light-dark(var(--color-dark-blue), var(--color-bone-oatmeal-1)) 0.5rlh, 1.5rlh,
var(--color-light-blue) 1.5rlh, 2.5rlh,
var(--color-tawny-rust-dark) 2.5rlh, 3.5rlh,
var(--color-background) 3.5rlh
); */
/* background-image: linear-gradient(
135deg,
var(--color-background) 0rlh, 0.75rlh,
light-dark(var(--color-dark-blue), var(--color-bone-oatmeal-1)) 0.75rlh, 1.5rlh,
var(--color-light-blue) 1.5rlh, 2.25rlh,
var(--color-tawny-rust-dark) 2.25rlh, 3rlh,
var(--color-background) 3rlh
); */
transition-property : color , background-color;
transition-duration : var ( --theme-transition-duration );
transition-timing-function : ease-out ;
/* Layering system:
Base content gets z-index 0-9
Nav gets 10-19
Modals etc get 20+
*/
z-index : 10 ;
}
.site-nav > * {
flex : 0 0 auto ;
}
.site-nav .current-page {
text-decoration : underline ;
text-decoration-color : var ( --color-accent );
text-decoration-thickness : 0.08 em ;
text-underline-offset : 0.09 em ;
}
.site-nav button {
width : 2.25 rem ;
height : 2.25 rem ;
color : inherit ;
padding : 0.15 em ;
text-align : inherit ;
font : unset ;
border : none ;
background-color : inherit ;
}
/* Dark mode toggle button */
button #themeToggle {
--theme-icon-rotation : 0 deg ;
}
:root [ data-theme = "dark" ] button #themeToggle {
--theme-icon-rotation : -180 deg ;
}
@media print {
.site-nav {
display : none ;
}
}
/* ****************************** */
/* COMPONENT: Homepage */
.homepage-main {
--wrap-width : 120 ch ;
font-size : var ( --size-2-rem );
--flow-space : 1 rlh ;
display : grid ;
grid-template-columns : 1 fr ;
gap : 2 rlh ;
align-items : start ;
justify-items : center ;
}
.homepage-main .homepage-bio-image {
max-width : 24 rem ;
margin-inline : auto ;
}
.homepage-main header h1 {
font-size : var ( --size-5-rem );
line-height : var ( --size-5-rlh );
/* Avoid wrapping on most phones and all the way up.
Scale to upper bound asap. */
font-size : clamp ( var ( --size-3-rem ), calc ( var ( --size-1-rem ) + 3.8 vw ), var ( --size-5-rem ));
/* We can stray from the vertical rhythm here */
line-height : 1 ;
}
/* Make homepage h2 subheading look like body text */
.homepage-main header h2 {
font-size : var ( --size-1-rem );
line-height : var ( --size-1-rlh );
margin-block-start : 0.5 rlh ;
}
:root [ data-theme = "light" ] .homepage-main header h2 {
font-weight : var ( --font-weight-light-mode );
}
:root [ data-theme = "dark" ] .homepage-main header h2 {
font-weight : var ( --font-weight-dark-mode );
}
.homepage-main .homepage-intro-text {
/* Use with serif */
--wrap-width : 58 ch ;
/* Use with sans-serif */
/* --wrap-width: 50ch; */
/* Use with serif */
margin-block-start : 4 rlh ;
/* Use with sans-serif */
/* margin-block-start: 2rlh; */
padding-inline : 0 ;
--flow-space : 1 rlh ;
}
@media ( min-width : 52 em ) {
.homepage-main {
grid-template-columns : 2 fr 3 fr ;
justify-items : start ;
}
.homepage-main header {
margin-block-start : 4 rlh ;
}
.homepage-main .homepage-bio-image {
margin-inline-end : 0 ;
}
}
/* ****************************** */
/* COMPONENT: Resume */
/* Use Grid so we don't have to style the child elements as well */
.resume-header {
display : grid ;
grid-template-columns : 1 fr ;
gap : 0.5 rlh ;
align-items : start ;
}
.logo-svg {
max-width : 6 rem ;
margin-inline : auto ;
}
@media ( min-width : 24 em ) {
.resume-header {
grid-template-columns : minmax ( 5 rem , 1 fr ) 4 fr ;
gap : 1 rlh ;
}
.logo-svg {
max-width : 100 % ;
}
}
@media screen and ( min-width : 60 em ) {
.resume-main.wrapper {
margin-inline : 15 % auto ;
}
}
/* Workaround: markdown lists don't have flow class */
.resume-main li {
margin-block-start : var ( --flow-space , 1 em );
}
/* Dialog element */
.resume-css-dialog {
position : fixed ;
/* Be on top of the nav */
z-index : 20 ;
top : max ( 1 rlh , env(safe-area-inset-top , 1 rlh ));
left : 0 ;
padding : 0 ;
/* max-width: 85em; */
height : 100 % ;
max-height : calc (
100 % - max ( 1 rlh , env(safe-area-inset-top , 1 rlh )) -
max ( 1 rlh , env(safe-area-inset-bottom , 1 rlh ))
);
border : 3 px solid var ( --color-fg );
border : none ;
box-shadow : 0 0 2.5 em -0.5 em light-dark( var ( --color-midnight-blue ), var ( --color-light-blue ));
background-color : #1e1e2e ; /* catppuccin-mocha bg */
background-color : #22272e ; /* github-dark-dimmed bg */
}
/* Dialog when it's in modal state */
.resume-css-dialog :modal {
display : flex ;
flex-flow : column nowrap ;
align-items : center ;
}
button #closeStylesheet {
margin : 0.5 rlh ;
}
.resume-css-dialog .shiki {
padding : 0.5 rlh ;
overflow : auto ;
scrollbar-gutter : stable;
max-inline-size : 100 % ;
max-block-size : 100 % ;
}
@media print {
.resume-header {
grid-template-columns : 5 rem 1 fr ;
gap : 1 rlh ;
}
}
/* ****************************** */
/* COMPONENT: Student Feedback */
.student-feedback-main blockquote p :nth-child ( 2 ) {
position : relative ;
--flow-space : 0 ;
}
.student-feedback-main blockquote p :nth-child ( 2 ) ::before {
content : "“" ;
font-size : 5 rem ;
line-height : 1 rem ;
/* I like the light blue in both modes, but it's not enough contrast
on the bone/oatmeal background (white was fine) */
/* color: var(--color-light-blue); */
color : light-dark( var ( --color-dark-blue ), var ( --color-light-blue ));
position : absolute ;
left : -0.5 em ;
top : 0.3 em ;
}
.student-feedback-main article {
--flow-space : 1 rlh ;
}
.blockquote-semester::before {
display : none ;
}
.chart-container {
aspect-ratio : 2 ;
}
.chart-canvas {
background-color : var ( --color-bone-oatmeal-2 );
max-width : 100 % ;
}
.chart-caption {
font-size : 0.875 em ;
}
Close