@import url('https://fonts.googleapis.com/css2?family=Tiny5&display=swap');
:root {
  /* surfaces — darkest to lightest */
  --forest-floor: #0D1210;  /* page background */
  --understory:   #141B18;  /* cards, sections */
  --canopy:       #1C2521;  /* raised surfaces, inputs */
  --moss-line:    #2A3630;  /* borders, dividers */

  /* greens */
  --deep-pine:    #2F5C43;  /* muted fills, badges */
  --fern:         #4A8C63;  /* primary buttons, links */
  --sage:         #7CB894;  /* hover states, active links */

  /* browns */
  --bark:         #3B2C21;  /* warm section blocks */
  --cedar:        #6B4F35;  /* secondary buttons, borders */
  --amber-resin:  #C08B5C;  /* highlights, small CTAs */

  /* text */
  --birch:        #dbd6c8;  /* headings, body */
  --lichen:       #9AA79D;  /* captions, meta */

  --step--2: clamp(0.75rem,  0.729rem + 0.09vw, 0.8125rem);  /* 12 → 13 */
  --step--1: clamp(0.875rem, 0.854rem + 0.09vw, 0.9375rem);  /* 14 → 15 */
  --step-0:  clamp(1rem,     0.958rem + 0.19vw, 1.125rem);   /* 16 → 18  body */
  --step-1:  clamp(1.125rem, 1.042rem + 0.37vw, 1.375rem);   /* 18 → 22  lead */
  --step-2:  clamp(1.1875rem,1.083rem + 0.46vw, 1.5rem);     /* 19 → 24  h4 */
  --step-3:  clamp(1.375rem, 1.167rem + 0.93vw, 2rem);       /* 22 → 32  h3 */
  --step-4:  clamp(1.625rem, 1.25rem  + 1.67vw, 2.75rem);    /* 26 → 44  h2 */
  --step-5:  clamp(2rem,     1.417rem + 2.59vw, 3.75rem);    /* 32 → 60  h1 */

  /* Two edges derived from one another. Card backgrounds sit on --card-edge;
     --gutter is that plus the cards' own padding, so a top-level card pulled
     out by --card-pad-x lands exactly on --card-edge and all text — titles,
     running text, card contents — lines up on --gutter.
     Defining it this way means the pull can never exceed the gutter, which is
     what pushed cards off the right of the page and caused sideways scroll. */
  --card-edge:  max(0.75rem, 1.9vw);
  --card-pad-x: 0.75rem;
  --gutter:     calc(var(--card-edge) + var(--card-pad-x));

  /* Optical alignment: at display sizes the glyphs' own left bearing makes a
     heading look inset even when its box is flush, so titles are nudged out. */
  --title-shift: 0.25rem;
}

*,
*::before,
*::after {
    box-sizing: border-box;   /* width: 100% + padding was overflowing to the right */
}

html {
    scrollbar-gutter: stable;   /* so locking scroll for a dialog doesn't shift the page */
}

body {
    background: var(--forest-floor);
    font-family: "Tiny5", sans-serif;
    font-weight: 400;
    font-style: normal;
    margin: 0;
}

::selection {
    background: var(--deep-pine);
}

.page-banner {
    max-width: 100%;
    display: block;
}
.page-title {
    color: var(--birch);
    display: block;
    font-size: var(--step-5);
    line-height: 1.1;      /* fluid font-size + normal leading = gap that grows with viewport */
    margin-top: 1.4vw;
    margin-bottom: 0.45vw;
    margin-left: calc(var(--gutter) - var(--title-shift));
}


/* desktop: description above structures in the left column, slider beside both */
#about {
    margin: 0 var(--gutter);   /* the section owns the gutter, same as #discussion */
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    /* Row 3 is slack for the slider. Without it the slider, spanning two auto
       rows, pads both with its leftover height, so the description row grew and
       shrank as the lists were expanded. Items crossing an fr track are left out
       of intrinsic row sizing, so rows 1 and 2 now follow their own content. */
    grid-template-rows: auto auto 1fr;
    gap: 0 2rem;          /* no row gap: .section-title's own margin-top spaces every section */
    align-items: start;   /* stretch would make the slider as tall as the whole column */
}
#about > * {
    min-width: 0;
}
.description {
    grid-area: 1 / 1;
}
#about > .about-section {
    grid-area: 2 / 1;
}
.image-slider {
    grid-area: 1 / 2 / -1 / auto;   /* spans down through the slack row */
}

.description {
    color: var(--lichen);
    font-size: var(--step-2);
    max-width: 60vw;
}
.download-button {
    display: flex;             /* block-level, so it sits on its own line */
    width: fit-content;
    align-items: center;
    gap: 0.6rem;
    margin-top: 1.2rem;
    padding: 0.6rem 1.1rem;
    color: var(--birch);
    background: var(--deep-pine);
    border: 1px solid var(--fern);
    border-radius: 12px;
    font-size: var(--step-1);
    text-decoration: none;
    transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.download-button:hover {
    background: var(--fern);
    border-color: var(--sage);
}
.download-button:active {
    color: var(--forest-floor);
    background: var(--sage);
    border-color: var(--sage);
}
.download-button:focus-visible {
    outline: 2px solid var(--amber-resin);
    outline-offset: 2px;
}
.download-button[hidden] {
    display: none;             /* the attribute alone loses to display: flex */
}

.download-icon {
    flex: 0 0 auto;
    width: 0.9em;
    height: 0.9em;
    shape-rendering: crispEdges;
}

@media (prefers-reduced-motion: reduce) {
    .download-button {
        transition: none;
    }
}

/* image slider — arrows overlay the image, revealed by hovering either side */
.image-slider {
    position: relative;
    display: block;
}
.image-slider[hidden] {
    display: none;
}

.slider-viewport {
    width: 100%;
    aspect-ratio: 16 / 10;
    background: var(--understory);
    border-radius: 12px;
    overflow: hidden;
}

.slider-image {
    width: 100%;
    height: 100%;
    display: block;
    object-fit: contain;
}

/* full-height hover zones pinned to each side of the image */
.slider-arrow {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 25%;
    display: flex;
    align-items: center;
    padding: 0 1rem;
    line-height: 0;
    background: none;
    border: none;
    cursor: pointer;
    transition: color 120ms ease;
}
.slider-arrow[data-dir="-1"] {
    left: 0;
    justify-content: flex-start;
}
.slider-arrow[data-dir="1"] {
    right: 0;
    justify-content: flex-end;
}

/* the icon, not the zone, is what fades in */
.slider-arrow .pixel-icon {
    opacity: 0;
    transition: opacity 150ms ease;
}
.slider-arrow:hover .pixel-icon,
.slider-arrow:focus-visible .pixel-icon {
    opacity: 1;
}
/* no hover on touch — keep them permanently visible there */
@media (hover: none) {
    .slider-arrow .pixel-icon {
        opacity: 1;
    }
}

@media (prefers-reduced-motion: reduce) {
    .slider-arrow,
    .slider-arrow .pixel-icon {
        transition: none;
    }
}
.slider-arrow:hover {
    color: var(--sage);
}
.slider-arrow:active {
    color: var(--deep-pine);
}
.slider-arrow:focus-visible {
    outline: none;
}
.slider-arrow[hidden] {
    display: none;
}

.pixel-icon {
    display: block;
    width: 1.75rem;
    height: 1.75rem;
    shape-rendering: crispEdges;
}

/* mobile: one column, everything in source order — description, slider, structures */
@media (max-width: 48rem) {
    #about {
        grid-template-columns: minmax(0, 1fr);
        grid-template-rows: auto;
        gap: 2rem;        /* stacked, so the rows need real separation again */
    }
    .description,
    #about > .about-section,
    .image-slider {
        grid-area: auto;
    }
    .description {
        max-width: none;
    }
}

.section-title {
    color: var(--birch);
    display: block;
    font-size: var(--step-4);
    line-height: 1.1;      /* fluid font-size + normal leading = gap that grows with viewport */
    margin-top: 1.4vw;
    margin-bottom: 0.45vw;
    margin-left: calc(-1 * var(--title-shift));
}

.section-text {
    color: var(--lichen);
    font-size: var(--step-1);
    line-height: 1.5;
    margin: 0 0 1rem;
}
.section-text strong {
    color: var(--birch);
}

.expandable {
    margin: 0 0 0.75rem;
    background: var(--forest-floor);
    border: 1px solid var(--moss-line);
    border-radius: 12px;
    overflow: hidden;      /* clips the summary bar to the rounded corners */
}

.expandable > summary {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    padding: 0.7rem var(--card-pad-x);
    color: var(--birch);
    background: var(--understory);
    font-size: var(--step-1);
    cursor: pointer;
    list-style: none;      /* hides the default triangle in Firefox */
    transition: background 120ms ease, color 120ms ease;
}
.expandable > summary::-webkit-details-marker {
    display: none;         /* and in Safari/Chrome */
}
.expandable > summary:hover,
.expandable > summary:focus-visible {
    background: var(--canopy);
    color: var(--sage);
    outline: none;
}

/* two static icons rather than one rotated one — rotation is a transform */
.expand-icon {
    flex: 0 0 auto;
    width: 0.7rem;
    height: 0.7em;
    shape-rendering: crispEdges;
}
.icon-open,
.expandable[open] .icon-closed {
    display: none;
}
.expandable[open] .icon-open {
    display: block;
}

.expandable-list {
    margin: 0;
    padding: 0.85rem 1rem 0.85rem 3rem;
    color: var(--lichen);
    font-size: var(--step-0);
    line-height: 1.8;
}

@media (prefers-reduced-motion: reduce) {
    .expandable > summary {
        transition: none;
    }
}

/* sign-in dialog — shown when posting or replying without an account */
.auth-dialog {
    /* fixed + inset 0 + auto margins centres on both axes; `relative` here would
       drop the dialog back into page flow and untie it from the viewport */
    position: fixed;
    inset: 0;
    margin: auto;
    width: min(26rem, calc(100vw - 2rem));
    height: fit-content;                    /* inset: 0 would stretch it otherwise */
    max-height: calc(100dvh - 2rem);
    overflow: auto;
    padding: 1.6rem;
    color: var(--birch);
    background: var(--understory);
    border: 1px solid var(--moss-line);
    border-radius: 12px;
}
.auth-dialog::backdrop {
    background: rgba(0, 0, 0, 0.65);
}

/* showModal() makes the page inert but still lets it scroll behind the dialog */
html:has(.auth-dialog[open]) {
    overflow: hidden;
}

.auth-title {
    margin: 0 0 0.6rem;
    font-size: var(--step-2);
    font-weight: 400;
    line-height: 1.1;
}
.auth-text {
    margin: 0 0 1.2rem;
    color: var(--lichen);
    font-size: var(--step-0);
    line-height: 1.5;
}
.auth-note {
    margin: 0.7rem 0 0;
    color: var(--lichen);
    font-size: var(--step--2);
    text-align: center;
}

.auth-close {
    position: absolute;
    top: 0.7rem;
    right: 0.7rem;
    display: flex;
    padding: 0.35rem;
    line-height: 0;
    color: var(--lichen);
    background: none;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    transition: color 120ms ease;
}
.auth-close:hover {
    color: var(--birch);
}
.auth-close:focus-visible {
    outline: 2px solid var(--amber-resin);
    outline-offset: 1px;
}
.close-icon {
    width: 0.95rem;
    height: 0.95rem;
    /* no crispEdges here — it would leave the diagonals jagged */
}

.github-button {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    width: 100%;
    padding: 0.7rem 1rem;
    color: var(--birch);
    background: var(--canopy);
    border: 1px solid var(--moss-line);
    border-radius: 8px;
    font-family: inherit;
    font-size: var(--step-0);
    cursor: pointer;
    transition: background 120ms ease, border-color 120ms ease;
}
.github-button:hover {
    background: var(--deep-pine);
    border-color: var(--fern);
}
.github-button:focus-visible {
    outline: 2px solid var(--amber-resin);
    outline-offset: 2px;
}
.github-icon {
    flex: 0 0 auto;
    width: 1.15em;
    height: 1.15em;
}

@media (prefers-reduced-motion: reduce) {
    .auth-close,
    .github-button {
        transition: none;
    }
}

/* discussion */
#discussion {
    margin: 0 var(--gutter);   /* matches #about */
}

/* Pulled out by their own padding so their text starts on the gutter, level with
   the titles and running text. Scoped to `>` so nested replies keep their indent.
   The structures expandables are deliberately NOT in this list: they carry a
   visible border, so an overhang reads as misalignment rather than disappearing
   the way a borderless background does. */
.post-list > .post,
.discussion-body > .composer {
    margin-left: calc(-1 * var(--card-pad-x));
    margin-right: calc(-1 * var(--card-pad-x));
}

.discussion-body {
    max-width: 60rem;
}

.post {
    padding: 0.85rem var(--card-pad-x);
    margin-bottom: 0.75rem;
    border-radius: 12px;
}

.post-notice {
    margin: 0.5rem 0;
    color: var(--lichen);
    font-size: var(--step--1);
}

.post-head {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    font-size: var(--step--1);
}

/* collapse sits at the head of the action row; expand replaces the whole post */
.collapse-toggle,
.expand-toggle,
.more-replies {
    display: flex;
    flex: 0 0 auto;
    align-items: center;
    gap: 0.45rem;
    padding: 0.2rem;
    line-height: 0;
    color: var(--lichen);
    background: none;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    transition: color 120ms ease;
}
.collapse-toggle:hover,
.expand-toggle:hover,
.more-replies:hover {
    color: var(--sage);
}
.collapse-toggle:focus-visible,
.expand-toggle:focus-visible,
.more-replies:focus-visible {
    outline: 2px solid var(--amber-resin);
    outline-offset: 1px;
}
.fold-icon {
    width: 0.8rem;
    height: 0.8rem;
    shape-rendering: crispEdges;
}

/* "N more replies" sits in the thread gutter, where the next reply would start */
.more-replies {
    padding: 0.35rem 0.2rem;
    font-family: inherit;
    font-size: var(--step--1);
    line-height: 1;
}

.post:not(.is-collapsed) > .post-head .expand-toggle {
    display: none;
}
.post.is-collapsed > .post-body,
.post.is-collapsed > .post-actions,
.post.is-collapsed > .reply-box,
.post.is-collapsed > .post-replies {
    display: none;
}
.post.is-collapsed {
    padding-top: 0.6rem;
    padding-bottom: 0.6rem;
}
.post-author {
    color: var(--sage);
}
.post-meta {
    color: var(--lichen);
}

.post-body {
    margin: 0.5rem 0 0.75rem;
    color: var(--birch);
    font-size: var(--step-0);
    line-height: 1.5;
    overflow-wrap: anywhere;   /* a 1000-word post can still hold one long word */
    white-space: pre-wrap;     /* keeps the line breaks people typed */
}

.post-deleted {
    color: var(--lichen);
}

.post-actions {
    display: flex;
    align-items: center;
    gap: 1rem;
}

.vote {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}
.vote-button {
    display: flex;
    padding: 0.25rem;
    line-height: 0;
    color: var(--lichen);
    background: none;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    transition: color 120ms ease, background 120ms ease;
}
.vote-button:hover {
    color: var(--birch);
    background: var(--canopy);
}
.vote-button:focus-visible {
    outline: 2px solid var(--amber-resin);
    outline-offset: 1px;
}
.vote-icon {
    width: 0.9rem;
    height: 0.9rem;
    shape-rendering: crispEdges;
}
.vote-score {
    min-width: 2.5ch;
    color: var(--lichen);
    font-size: var(--step--1);
    text-align: center;
}
.voted-up .vote-score,
.voted-up .vote-button[aria-pressed="true"] {
    color: var(--fern);
}
.voted-down .vote-score,
.voted-down .vote-button[aria-pressed="true"] {
    color: var(--amber-resin);
}

.text-button {
    padding: 0.25rem 0.4rem;
    color: var(--lichen);
    background: none;
    border: none;
    border-radius: 4px;
    font-family: inherit;
    font-size: var(--step--1);
    cursor: pointer;
    transition: color 120ms ease, background 120ms ease;
}
.text-button:hover {
    color: var(--sage);
    background: var(--canopy);
}
.text-button:focus-visible {
    outline: 2px solid var(--amber-resin);
    outline-offset: 1px;
}

/* replies are indented against a thread line, any depth deep */
.post-replies:not(:empty) {
    margin: 0.75rem 0 0 0.5rem;
    padding-left: 0.9rem;
    border-left: 2px solid var(--moss-line);
}
.post-replies .post:last-child {
    margin-bottom: 0;
}
.composer {
    margin: 1.25rem 0;
    padding: 0.85rem var(--card-pad-x);
    border-radius: 12px;
}
.composer-inline {
    margin: 0.75rem 0 0;
    background: none;
}

/* the new-post box heads the list and stays there */
#composer {
    margin-top: 0;
}
.composer-label {
    display: block;
    margin-bottom: 0.5rem;
    color: var(--lichen);
    font-size: var(--step--1);
}
.composer-input {
    width: 100%;
    max-width: 100%;   /* textareas ignore the parent's width without this */
    padding: 0.6rem 0.7rem;
    color: var(--birch);
    background: none;
    border: 1px solid var(--moss-line);
    border-radius: 8px;
    font-family: inherit;
    font-size: var(--step-0);
    line-height: 1.5;
    resize: none;
}
.composer-input::placeholder {
    color: var(--lichen);
}
.composer-input:focus-visible {
    outline: none;
    border-color: var(--deep-pine);
}
.composer-user {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.6rem;
    color: var(--lichen);
    font-size: var(--step--2);
}
.composer-user[hidden] {
    display: none;   /* the attribute alone loses to display: flex */
}
.composer-user strong {
    color: var(--sage);
    font-weight: 400;
}

.composer-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-top: 0.6rem;
}
.composer-count {
    color: var(--lichen);
    font-size: var(--step--2);
}
.composer-count.over-limit {
    color: var(--amber-resin);
}

.send-button,
.view-more {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.45rem 0.9rem;
    color: var(--birch);
    background: var(--deep-pine);
    border: 1px solid var(--fern);
    border-radius: 8px;
    font-family: inherit;
    font-size: var(--step--1);
    cursor: pointer;
    transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.send-button:hover:not(:disabled),
.view-more:hover {
    background: var(--fern);
    border-color: var(--sage);
}
.send-button:focus-visible,
.view-more:focus-visible {
    outline: 2px solid var(--amber-resin);
    outline-offset: 2px;
}
.send-button:disabled {
    color: var(--lichen);
    background: var(--canopy);
    border-color: var(--moss-line);
    cursor: not-allowed;
}
.send-icon {
    width: 0.8rem;
    height: 0.8rem;
    shape-rendering: crispEdges;
}

.view-more {
    width: fit-content;   /* block-level flex box, so it stays at the left edge */
    padding: 0.6rem 0.9rem;
}
.view-more[hidden] {
    display: none;      /* the attribute alone loses to display: flex */
}

@media (prefers-reduced-motion: reduce) {
    .vote-button,
    .text-button,
    .send-button,
    .view-more,
    .collapse-toggle,
    .expand-toggle,
    .more-replies {
        transition: none;
    }
}