/* Reset browser styles */
* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
    border: 0;
    vertical-align: bottom;
}

/* Initial setup
==============================================================================*/

/* The website is designed to imitate the appearance of a dot grid bullet
   journal, my preferred physical format for taking notes. For this reason, the
   placement of elements is carefully considered such that everything ends up
   aligned to a grid.
*/
:root {
    --grid-size: 1.5rem;
    --sidebar-size: calc(var(--grid-size)*10);
    --main-size: calc(var(--grid-size)*28);

    color-scheme: light dark;
    --bg1: light-dark(hsl(240 4 92), hsl(240 4 8));
    --bg2: light-dark(hsl(0 0 85), hsl(0 0 15));
    --text: light-dark(hsl(0 0 5), hsl(0 0 95));
    --subtext: light-dark(hsl(240 8 45), hsl(240 8 55));
    --link: light-dark(hsl(204 28 33), hsl(204 28 67));
    --link-hover: light-dark(hsl(204 50 50), hsl(204 50 50));
}

/* The body contains only two elements: the sidebar and the main div. */
body {
    display: flex;
    flex-direction: row;
    gap: var(--grid-size);

    max-width: /* Add the padding too, since we are using border-box sizing. */
        calc(var(--sidebar-size) + var(--main-size) + var(--grid-size)*3);
    min-height: calc(100vh - var(--grid-size)*2);
    margin: var(--grid-size) auto;
    padding: 0 var(--grid-size);

    font-family: 'Space Grotesk', sans-serif;
    font-size: calc(var(--grid-size)*2/3);
    line-height: var(--grid-size);
    color: var(--text);

    background-color: var(--bg1);
}

.sidebar {
    flex-basis: var(--sidebar-size);
}

.main {
    width: 100%;
    max-width: calc(100% - var(--sidebar-size) - var(--grid-size));
}

/* Generate the dot grid background, but only on the elements where content will
   actually be drawn.
*/
.main, .sidebar {
    background-color: var(--bg1);
    background-image: radial-gradient(var(--bg2) .1rem, transparent 0);
    background-size: var(--grid-size) var(--grid-size);
    background-position: calc(var(--grid-size)/2) calc(var(--grid-size)/2);
}

/* Now that the appearance of our "dot grid bullet journal" has been
   initialized, lets set some ground rules for how we'll write content onto the
   page.
*/
article > * + *, aside > * + *, blockquote > * + *, section > * + *,
.main > * + *, .sidebar  > * + * {
    margin-top: var(--grid-size);
}

/* Sidebar
==============================================================================*/

/* The logo is always a fixed size. */
.logo {
    display: block;
    width: var(--sidebar-size);
    height: calc(var(--grid-size)*4);
}

/* Custom style for the search bar. */
.search {
    display: flex;
    flex-direction: row;

    input[type=text] {
        border: none;
        max-width: calc(var(--sidebar-size) - var(--grid-size));
        height: var(--grid-size);
        padding: 0 calc(var(--grid-size)/2);
        background-color: var(--bg2);
        color: var(--text);
        border-radius: calc(var(--grid-size)/4);
        font-family: 'Space Mono', monospace;
        font-size: calc(var(--grid-size)*2/3);
    }
}

/* We want to render things like footnotes, the table of contents, and the logo
   onto the side where the sidebar is. This puts floats those elements in the
   sidebar when the screen is wide enough and inlines them otherwise.
*/
.side, .sidenote {
    float: left;
    clear: both;
    position: relative;
    right: calc(var(--sidebar-size) + var(--grid-size));
    width: var(--sidebar-size);
    margin-inline-end: calc(-1 * var(--sidebar-size));
}

.sidenote {
    color: var(--subtext);
    text-align: right;
    text-wrap: balance;
}

/* We don't actually render content in the sidebar directly. Instead, we float
   elements into the space that the sidebar occupies. This allows us to do
   sidenotes. However, we need to reposition the floated content on mobile
   devices so it can be seen.

   Unfortunately, we can't use variables in the media query. We want to switch
   when the main content is less than twice the size of the sidebar.
*/
@media all and (width < 49.5rem) {
    body {
        flex-direction: column;
    }

    .sidebar {
        flex-basis: 0;
    }

    .main {
        width: 100%;
        max-width: 100%;
    }

    .side, .sidenote {
        float: unset;
        display: block;
        position: initial;
        width: round(down, 100%, var(--grid-size));
        margin-inline-end: 0;
    }

    .sidenote {
        padding: calc(var(--grid-size)/2);
        text-align: left;
        text-wrap: wrap;
        color: var(--text);
        background-color: var(--bg2);
        border-radius: calc(var(--grid-size)*.3);
    }
}

/* The nav is the "first" element in the main page, but it will have a margin
   due to the usual rules for adding space between elements even though the
   logo that comes before it is floated to the side. This removes that extra
   margin.
*/
@media all and (width >= 49.5rem) {
    nav {
        margin-top: 0 !important;
    }
}

/* Sections
==============================================================================*/

/* Different "types" of content in the sidebar and main elements are contained
   in different sections. This adds a unique style to the headers of those
   sections to make them distinct from the other elements of the page.

   The nav and footer elements are not really sections since they don't contain
   any child content, but since they live at the same logical level in the
   document it makes sense to apply the same visual style.
*/
section > h1, nav, footer {
    font-family: 'Space Mono', monospace;
    font-size: calc(var(--grid-size)*2/3);
    line-height: var(--grid-size);
    color: var(--subtext);

    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    gap: calc(var(--grid-size)/2);
}

/* Draws a line at the bottom of the section header */
section > h1::after {
    content: "";
    flex: 1;
    margin-left: 1rem;
    height: 0.1rem;
    background-color: var(--subtext);
    align-self: end;
}

/* General styles
==============================================================================*/

/* Draw a box around the target element. We use an outline instead of a border,
   because the outline doesn't take up space on the document and thus won't
   disrupt the grid-aligned placement of other elements.
*/
:target {
    outline: solid 0.1rem var(--subtext);
}

/* Used for special title headers that have a background image.
*/
.banner {
    background-size: cover;
    background-position: center;
    min-height: calc(var(--grid-size) * 10);
    padding: var(--grid-size);
    padding-top: calc(var(--grid-size) * 7);
}

/* Headers are larger than the normal text, but even though each header level
   has a different size, we use the same line height so the content is aligned
   to the grid.
*/
h1 {
    font-size: calc(var(--grid-size)*1.2);
    line-height: calc(var(--grid-size)*2);
}

h2 {
    font-size: var(--grid-size);
    line-height: calc(var(--grid-size)*2);
}

h3 {
    font-size: calc(var(--grid-size)*0.8);
    line-height: calc(var(--grid-size)*2);
}

a {
    color: var(--link);
    text-decoration: none;

    &:hover {
        color: var(--link-hover);
    }
}

sup {
    display: inline-block;
    padding-right: calc(var(--grid-size) * .25)
}

ol, ul {
    padding-inline-start: calc(var(--grid-size));

    li::marker {
        color: var(--subtext);
        line-height: calc(var(--grid-size) * .75);
    }
}

blockquote {
    border-left: solid 0.2rem var(--subtext);
    margin-right: var(--grid-size);
    padding-left: calc(var(--grid-size) - 0.2rem);
}

/* Image sizing is a bit tricky. We want the images to take up 100% of the
   width and then resize the height to the appropriate value to maintain the
   aspect ratio. However, we also want the height to be a multiple of the grid
   size so that elements after the image are aligned correctly.

   So, we need to set the height of the image manually. We do this by adding the
   image aspect ratio as an element style when generating the HTML, and then use
   that along with the width of the parent to find the size of the height.
   Finally, we round that height up to the nearest grid size.

   However, in order to get the width of the parent while calculating the
   height, we need to make the parent of the image into a container so we can
   get access to the cqi unit.
*/
article > p:has(> img), figure:has(> img) {
    container-type: inline-size;

    img {
        width: 100%;
        max-height: round(down, 40vh, var(--grid-size));
        height: round(up, calc(100cqi / var(--ratio)), var(--grid-size));
        object-fit: contain;
    }
}

figcaption {
    text-align: center;
    color: var(--subtext);
    margin-left: var(--grid-size);
    margin-right: var(--grid-size);
    margin-top: var(--grid-size);
}

time {
    font-family: 'Space Mono', monospace;
}

/* We have to move this element up a little bit if we want it to appear exactly
   on the grid.
*/
hr {
    border-bottom: solid var(--bg2) 2px;
    margin-top: calc(var(--grid-size) - 1px);
    margin-bottom: -1px;
}

/* Tables are a bit tricky. We want to draw them aligned to the grid, but the
   only way we can draw grid lines is by adding a border, which this changes the
   size of our element.

   This causes a few issues:
   - We have to use the px unit to define the border. Otherwise, a lack of
     precision causes the dimensions of our table to be slightly off.
   - We can no longer have table cells with the same height as the grid cells,
     because the line height is already the same height as the grid and I don't
     want to make the text smaller. So, we have to add additional padding such
     that the entire table cell is exactly two grid cells tall.
*/
table {
    width: round(down, 100%, var(--grid-size));
    overflow-x: scroll;
    border-collapse: collapse;

    th, td {
        border: solid 2px var(--bg2);
        padding: calc(var(--grid-size)/2 - 1px);
        vertical-align: top;
        word-break: break-word;
    }

    /* For reasons unknown to me, even though we have no margin or padding,
       there is always a gap between the header and the first table row equal
       to the height of the border.
    */
    tr:first-child > td {
        padding-top: calc(var(--grid-size)/2 - 3px);
    }
}

/* File listings */
.listing {
    /* Shrink the first column; that's where our timestamp is. */
    th:first-child, td:first-child {
        width: 0.1%;
        white-space: nowrap;
    }

    /* Make the icon less bright. */
    i {
        color: var(--subtext);
    }
}

/* Task list
==============================================================================*/

/* A task list is a list of items that I have or have not checked. This is a
   common pattern in note-taking software, and they are normally rendered such
   that the checkbox is used instead of the bullet point.
*/
li:has(label > input[type="checkbox"]) {
    list-style: none;

    /* TODO: Add the disabled attribute to the checkboxes instead. Doing this
       here causes the mouse to behave differently on the list text.
    */
    pointer-events: none;
}

label:has(input[type="checkbox"]:checked) {
    color: var(--subtext);
}

/* Provide a custom checkbox appearance. */
input[type="checkbox"] {
    appearance: none;
    width: calc(var(--grid-size) * 3 / 4);
    height: calc(var(--grid-size) * 3 / 4);

    /* Move the entire checkbox to where the bullet point would have gone. Using
       the margin-inline-* properties makes it so that when text stays indented
       at the same level when it flows onto the next line.
    */
    margin-inline-start: calc(var(--grid-size)*-7/8);
    margin-inline-end: calc(var(--grid-size) / 8);

    border: solid 0.1rem var(--bg2);
    border-radius: calc(var(--grid-size) / 5);

    &:checked {
        background-color: var(--bg2);
    }

    /* Funny CSS code for rendering the checkmark. I could probably change this
       to use an SVG instead, but then the browser would have to make another
       request to fetch the SVG.
    */
    &:checked::after {
        content: "";
        display: block;
        position: relative;
        left: calc(var(--grid-size)/6);
        width: calc(var(--grid-size)/5);
        height: calc(var(--grid-size)*2/5);
        transform: rotate(45deg);
        border: solid var(--bg1);
        border-width: 0 0.2rem 0.2rem 0;
    }
}

/* Code styles
==============================================================================*/

/* Inline code */
code {
    font-family: 'Space Mono', monospace;
    tab-size: 4;

    background-color: var(--bg2);
    border-radius: calc(var(--grid-size)*.3);
    padding: 0 calc(var(--grid-size)/4);
}

/* Code blocks */
pre > code {
    font-size: calc(var(--grid-size)*0.6);
    background-color: unset;
    padding: 0;
    display: flex;
    flex-direction: column;
    overflow-x: scroll;
}

pre > code::before {
    counter-reset: listing;
}

pre > code > span {
    counter-increment: listing;
    margin-top: 0 !important;
    gap: 1ex;
    margin-left: var(--grid-size);
}

pre > code > span::before {
    content: counter(listing);
    display: inline-block;
    min-width: calc(var(--grid-size));
    padding-right: calc(var(--grid-size) / 4);
    margin-left: calc(var(--grid-size) * -1.25);

    text-align: right;
    color: var(--subtext);
}

pre > code > span > a {
    display: none;
}

/* Pandoc's built-in monochrome style, generated by adding $highlighting-css$
   to a template and changing the writerHighlightStyle to monochrome.
*/
code span.al { font-weight: bold; } /* Alert */
code span.an { font-style: italic; } /* Annotation */
code span.cf { font-weight: bold; } /* ControlFlow */
code span.co { font-style: italic; } /* Comment */
code span.cv { font-style: italic; } /* CommentVar */
code span.do { font-style: italic; } /* Documentation */
code span.dt { text-decoration: underline; } /* DataType */
code span.er { font-weight: bold; } /* Error */
code span.in { font-style: italic; } /* Information */
code span.kw { font-weight: bold; } /* Keyword */
code span.pp { font-weight: bold; } /* Preprocessor */
code span.wa { font-style: italic; } /* Warning */

/* Third-party elements
==============================================================================*/

/* Remixicon icons */
[class^="ri-"] {
    display: inline-block;
    width: var(--grid-size);
    text-align: center;
}

/* Embeds */
p:has(> iframe) {
    container-type: inline-size;

    iframe {
        width: 100%;
        height: round(up, calc(100cqi / (16 / 9)), var(--grid-size));
        color-scheme: auto; /* Needed for transparent iframes. */
    }
}

/* Manually-applied styles
==============================================================================*/

.meta {
    font-family: 'Space Mono', monospace;
    font-size: calc(var(--grid-size)*2/3);
    color: var(--subtext);
    white-space: preserve;
}

/* Unique style for a banner on the homepage. */
.home-banner {
    display: flex;
    flex-direction: row;
    align-items: center;
    column-gap: var(--grid-size);

    > div {
        display: flex;
        flex-direction: column;
        row-gap: var(--grid-size);
    }

    img {
        width: calc(var(--grid-size)*5);
        height: calc(var(--grid-size)*5);
        border-radius: var(--grid-size);
    }

    span {
        display: inline-block;
        break-inside: avoid;
    }
}

/* Unique style for project banners on the homepage. */
.project-banner {
    position: relative;
    max-width: round(down, 100%, var(--grid-size));
    min-height: calc(var(--grid-size) * 6);

    a p:not(:has(img)) {
        position: relative;
        padding: var(--grid-size);
        padding-top: calc(var(--grid-size) * 3);
        z-index: 1;

        font-size: calc(var(--grid-size)*1.2);
        line-height: calc(var(--grid-size)*2);
        color: black;

        filter: invert(1);
        mix-blend-mode: difference;
    }

    a img {
        position: absolute;
        width: 100%;
        height: 100%;
        object-fit: cover;
        filter: saturate(50%) blur(calc(var(--grid-size)/20));
        transition: filter 0.5s;
        clip-path: inset(0)
    }

    a:hover img {
        filter: saturate(100%) blur(0);
    }
}

/* Used when I want to layout elements horizontally. */
.flex {
    display: flex;
    flex-wrap: wrap;
    column-gap: var(--grid-size)
}

/* Animations
==============================================================================*/

@media all and (prefers-reduced-motion: no-preference) {
    html {
        scroll-behavior: smooth;
    }

    a {
        transition: color 0.5s;
    }

    :target {
        animation: target-fade 1s;
        outline: solid 0.1rem transparent;
    }

    @keyframes target-fade {
        0% { outline-color: transparent; }
        20% { outline-color: var(--subtext); }
        80% { outline-color: var(--subtext); }
        100% { outline-color: transparent; }
    }
}

/* Baskiv
==============================================================================*/

/* Baskiv is a language I made up when I was in high school when I was
   interested in constructed languages, and I have some documents which use a
   special font I made to render Baskiv characters.
*/
@font-face {
  font-family: baskiv;
  src: url('/baskiv.ttf');
}

.baskiv {
    font-family: baskiv;
}
