@font-face {
    font-family: 'ABC Areal Semi Mono';
    src: url('fonts/ABCArealSemiMono-Regular.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'ABC Areal Semi Mono';
    src: url('fonts/ABCArealSemiMono-Bold.woff2') format('woff2');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'ABC Areal Semi Mono';
    src: url('fonts/ABCArealSemiMono-RegularItalic.woff2') format('woff2');
    font-weight: 400;
    font-style: italic;
    font-display: swap;
}

/* Korean text falls back to Favorit Hangul; only fetched when Hangul is on screen. */
@font-face {
    font-family: 'ABC Favorit Hangul';
    src: url('fonts/ABCFavoritHangul-Regular.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
    unicode-range: U+1100-11FF, U+3130-318F, U+AC00-D7AF;
}

@font-face {
    font-family: 'ABC Favorit Hangul';
    src: url('fonts/ABCFavoritHangul-Medium.woff2') format('woff2');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
    unicode-range: U+1100-11FF, U+3130-318F, U+AC00-D7AF;
}

:root {
    --bg: #cde3ff;
    --bg-clear: rgb(205 227 255 / 0);
    --stick: 24px;
    --col: 402px;       /* width of the page column */
    --ink: #000;
    --gutter: 16px;
    --ease: cubic-bezier(0.22, 1, 0.36, 1);
    --spin: cubic-bezier(0.34, 1.4, 0.44, 1);
}

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html {
    background: var(--bg);
    -webkit-text-size-adjust: 100%;
}

body {
    font-family: 'ABC Areal Semi Mono', 'ABC Favorit Hangul', ui-monospace, 'SF Mono', Menlo, monospace;
    font-size: 14px;
    line-height: 1.3;
    color: var(--ink);
    background: var(--bg);
    -webkit-font-smoothing: antialiased;
}

ul {
    list-style: none;
}

a {
    color: inherit;
    text-decoration: none;
}

.u,
a:hover,
a:focus-visible {
    text-decoration: underline;
    text-decoration-skip-ink: none;
    text-underline-position: from-font;
}

/* List links stay plain, even on hover. */
.rows a:hover,
.rows a:focus-visible {
    text-decoration: none;
}

/* Tap-to-copy email */
.copy {
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    letter-spacing: inherit;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.copy:hover,
.copy:focus-visible {
    text-decoration: underline;
    text-decoration-skip-ink: none;
    text-underline-position: from-font;
    outline: none;
}

.copy.is-copied {
    text-decoration: none;
}

/* ---------- Page frame (Figma: iPhone 17, 402 wide, 16px gutters) ---------- */

.page {
    position: relative;
    display: flex;
    flex-direction: column;
    width: 100%;
    max-width: 402px;
    margin: 0 auto;
    min-height: 100vh;
    min-height: 100svh;
    padding: 72px var(--gutter) 36px;
}

.lede {
    font-size: 20px;
    font-weight: 400;
    line-height: 1.2;
    letter-spacing: -0.6px;
    /* Fallback; main.js locks this to the tallest phrase at the current width. */
    min-height: 2.4em;
}

/* Headline letters. Every letter of the current phrase is always laid out, so
   line breaks never move while it animates; .on only controls visibility. */
.typed .w {
    display: inline-block;
    white-space: nowrap;
}

.typed .c {
    display: inline-block;
}

/* a — typewriter: letters snap on and off. */
.lede[data-variant="a"] .c {
    opacity: 0;
}

.lede[data-variant="a"] .c.on {
    opacity: 1;
}

/* b — each letter eases in out of a blur, and back into it. */
.lede[data-variant="b"] .c {
    opacity: 0;
    filter: blur(6px);
    transition: opacity 0.32s ease-in, filter 0.32s ease-in;
}

.lede[data-variant="b"] .c.on {
    opacity: 1;
    filter: blur(0);
    transition: opacity 0.6s ease-out, filter 0.6s ease-out;
}

/* c — the same, a whole word at a time. */
.lede[data-variant="c"] .w {
    opacity: 0;
    filter: blur(8px);
    transition: opacity 0.4s ease-in, filter 0.4s ease-in;
}

.lede[data-variant="c"] .w.on {
    opacity: 1;
    filter: blur(0);
    transition: opacity 0.8s ease-out, filter 0.8s ease-out;
}

.measure {
    position: absolute !important;
    left: var(--gutter);
    right: var(--gutter);
    top: 0;
    min-height: 0;
    visibility: hidden;
    pointer-events: none;
}

/* With JS, the sentence stays hidden until the typing starts. */
.js .typed:not(.is-on) {
    visibility: hidden;
}

.lede strong {
    font-weight: 700;
}

.spacer {
    flex: 1 0 32px;
}

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* ---------- Two pages: home and curation ----------
   Moving between them slides both vertically, as one continuous sheet. */

.view {
    min-height: 100vh;
    min-height: 100svh;
    background: var(--bg);
}

.view[hidden] {
    display: none;
}

html.is-paging,
html.is-paging body {
    overflow: hidden;
}

html.is-paging .view {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    min-height: 0;
    overflow: hidden;
    will-change: transform;
}

.pager {
    display: block;
    width: 32px;
    height: 32px;
    border: 0;
    background: none;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
}

.pager img {
    display: block;
    transition: transform 0.5s var(--spin);
}

/* Hidden at rest. Pulling past the bottom of the page grows it from a speck to
   full size: --pull runs 0 → 1, --gap is the browser's own overscroll, if any. */
.pager-down {
    position: fixed;
    left: 50%;
    bottom: 0;
    z-index: 4;
    margin-left: -16px;
    opacity: calc(var(--pull, 0) * 1.4 - 0.15);
    /* Sits in the page's bottom margin; rides up into the gap where the browser rubber-bands. */
    transform: translateY(calc(min(-2px, var(--gap, 0px) * -0.5 + 16px))) scale(calc(0.1 + var(--pull, 0) * 0.9));
    pointer-events: none;
}

.pager-down.is-armed img {
    transform: scale(1.25);
    transition: transform 0.25s var(--spin);
}

.pager-down.is-settling {
    transition: opacity 0.25s ease, transform 0.35s var(--ease);
}

.pager-down:focus-visible {
    opacity: 1;
    transform: translateY(-8px);
    pointer-events: auto;
}

html.is-paging .pager-down {
    visibility: hidden;
}

/* The dots wait at nothing, then land one after another once the page has arrived. */
.pager-dots {
    display: block;
    fill: currentColor;
    overflow: visible;
    transition: transform 0.5s var(--spin);
}

.pager-dots circle {
    transform-box: fill-box;
    transform-origin: center;
    transform: scale(0);
}

.view.is-arrived .pager-dots circle {
    transform: none;
    animation: dot-in 0.32s var(--spin) both;
}

.view.is-arrived .pager-dots circle:nth-child(1) { animation-delay: 0s; }
.view.is-arrived .pager-dots circle:nth-child(2) { animation-delay: 0.14s; }
.view.is-arrived .pager-dots circle:nth-child(3) { animation-delay: 0.28s; }

/* The travelling arrow during a page turn; the real ones wait out of sight. */
.pager-ghost {
    position: fixed;
    top: 0;
    left: 50%;
    z-index: 20;
    width: 32px;
    height: 32px;
    margin-left: -16px;
    pointer-events: none;
}

html.is-paging .pager-up {
    visibility: hidden;
}

@media (hover: hover) and (pointer: fine) {
    .pager-up:hover .pager-dots {
        transform: translateY(-3px);
    }
}

.pager:focus-visible {
    outline: 1px solid currentColor;
    outline-offset: 4px;
    border-radius: 50%;
}

/* The back arrow floats at the top; content fades out beneath it. */
.cur-top {
    position: sticky;
    top: 0;
    z-index: 5;
    display: flex;
    justify-content: center;
    height: 64px;
    padding-top: 16px;
    background: linear-gradient(to bottom, var(--bg) 70%, var(--bg-clear));
    pointer-events: none;
}

.cur-top .pager {
    pointer-events: auto;
}

.cur-page {
    min-height: 0;
    padding-top: 8px;
    padding-bottom: 72px;
}

.cur-page .lede {
    min-height: 0;
}

/* Are.na feed */
.arena-tools {
    display: flex;
    justify-content: space-between;
    margin-top: 24px;
}

.cols {
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    cursor: pointer;
    opacity: 0.5;
    -webkit-tap-highlight-color: transparent;
}

.cols:hover,
.cols:focus-visible {
    opacity: 1;
    outline: none;
}

/* Columns are built by main.js, which keeps them level as blocks arrive. */
.arena {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin-top: 16px;
}

.arena-col {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.arena[data-cols="1"] .arena-col {
    gap: 28px;
}

.blk {
    display: block;
}

/* Blocks fade in one after another as they become ready (see main.js). */
/* Blocks rise in with the same move as list rows. */
.blk {
    transition: opacity 0.52s var(--ease), transform 0.52s var(--ease);
}

.blk.is-waiting {
    opacity: 0;
    transform: translateY(10px);
    transition: none;
}

/* Image blocks open large over the page. */
.blk-zoom {
    cursor: zoom-in;
    -webkit-tap-highlight-color: transparent;
}

.blk-zoom:focus-visible {
    outline: 1px solid currentColor;
    outline-offset: 2px;
}

.lightbox {
    position: fixed;
    inset: 0;
    z-index: 30;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px 16px;
    background: rgb(150 184 232 / 0);
    -webkit-backdrop-filter: blur(0);
    backdrop-filter: blur(0);
    cursor: zoom-out;
    transition: background 0.5s ease, backdrop-filter 0.5s ease, -webkit-backdrop-filter 0.5s ease;
}

.lightbox.is-on {
    /* The page's own sky, a touch deeper, over a blur of what is behind. */
    background: rgb(150 184 232 / 0.32);
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
}

.lightbox img {
    display: block;
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    will-change: transform;
}

html.has-lightbox {
    overflow: hidden;
}

/* An image that arrives after its block was shown fades in on its own. */
.blk img.is-late {
    opacity: 0;
}

.blk img {
    transition: opacity 0.4s ease;
}

.blk img {
    display: block;
    width: 100%;
    height: auto;
    background: rgb(0 0 0 / 0.04);
}

.blk img:not(:last-child) {
    margin-bottom: 8px;
}

.blk-title,
.blk-src {
    display: block;
    overflow-wrap: anywhere;
}

.blk-src {
    opacity: 0.5;
}

/* Text blocks sit in a box, the way Are.na shows them: a square in two
   columns, a shallower one in a single column. Long notes fade out at the bottom. */
.blk-note {
    aspect-ratio: 1;
    padding: 12px;
    border: 1px solid rgb(0 0 0 / 0.18);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.arena[data-cols="1"] .blk-note {
    aspect-ratio: 16 / 9;
}

.blk-text {
    flex: 1;
    min-height: 0;
    overflow: hidden;
    white-space: pre-line;
    overflow-wrap: anywhere;
    -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 24px), transparent);
    mask-image: linear-gradient(to bottom, #000 calc(100% - 24px), transparent);
}

a.blk:hover,
a.blk:focus-visible {
    text-decoration: none;
}

.arena-note {
    opacity: 0.5;
}

/* ---------- Sections ---------- */

.sec {
    margin-top: 8px;
}

.sec[data-sec="events"] {
    margin-top: 0;
}

.sec[data-sec="thoughts"] {
    margin-top: 28px;
}

.head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 32px;
}

.sec-about .head {
    justify-content: flex-end;
}

.label {
    font-size: 14px;
    font-weight: 700;
    line-height: 1.2;
}

/* ---------- Toggle: five dots, "+" at rest, turns 45° into "×" when open ---------- */

.toggle {
    display: block;
    width: 32px;
    height: 32px;
    border: 0;
    background: none;
    color: inherit;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
}

.toggle:focus-visible {
    outline: 1px solid currentColor;
    outline-offset: 4px;
    border-radius: 50%;
}

.dots {
    display: block;
    transition: transform 0.7s var(--spin);
}

.sec.is-open .dots {
    transform: rotate(45deg);
}

.toggle:active .dots {
    transition-duration: 0.15s;
    scale: 0.88;
}

/* ---------- About ---------- */

.body {
    margin-top: 8px;
}

.block + .block,
.extra + .block,
.block + .extra {
    margin-top: 1.3em;
}

/* One rendered line of a paragraph while it reveals line by line (see main.js). */
.ln {
    display: block;
    white-space: nowrap;
}

/* Clock colons blink once a second. */
.colon {
    animation: colon 1s steps(1) infinite;
}

@keyframes colon {
    50% { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
    .colon {
        animation: none;
    }
}

/* ---------- Lists (events, thoughts) ---------- */

.rows {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 1px;
}

.rows li {
    display: flex;
    justify-content: space-between;
    gap: 16px;
    line-height: 17px;
}

.rows li span:last-child:not(:first-child) {
    flex: none;
    text-align: right;
}

.sec.is-open .rows {
    gap: 12px;
    margin-top: 5px;
}

/* ---------- Open / closed states ---------- */

.sec:not(.is-open) .extra {
    display: none;
}

/* When one section is open, it takes the top slot and the others leave the flow. */
.page.has-open .spacer {
    display: none;
}

.page.has-open .sec {
    margin-top: 8px;
}

.page.has-open .sec:not(.is-open) {
    position: absolute;
    left: var(--gutter);
    right: var(--gutter);
    visibility: hidden;
    pointer-events: none;
}

/* ---------- Sticky header (open sections) ----------
   The headline scrolls up a little, then sticks; the open section's header row
   (label + ×) sticks right under it. Content scrolls beneath and fades out under
   a sky-coloured gradient. The backdrop only appears once the page is scrolled. */

.page.has-open .lede {
    position: sticky;
    top: var(--stick);
    z-index: 3;
}

.sec.is-open .head {
    position: sticky;
    top: calc(var(--stick) + var(--lede-h, 48px) + 16px);
    z-index: 2;
}

.page.has-open .lede::before,
.sec.is-open .head::before,
.sec.is-open .head::after {
    content: '';
    position: absolute;
    left: calc(var(--gutter) * -1);
    right: calc(var(--gutter) * -1);
    z-index: -1;
    background: var(--bg);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease;
}

.page.has-open .lede::before {
    top: -120px;
    bottom: 0;
}

.sec.is-open .head::before {
    top: -16px;
    bottom: 0;
}

.sec.is-open .head::after {
    top: 100%;
    height: 28px;
    background: linear-gradient(to bottom, var(--bg), var(--bg-clear));
}

.page.is-scrolled.has-open .lede::before,
.page.is-scrolled .sec.is-open .head::before,
.page.is-scrolled .sec.is-open .head::after {
    opacity: 1;
}

/* ---------- Detail pages (posts, profile) ----------
   Figma "iPhone 17 - 7": "<" at 16/16, title at 64, body at 144. */

/* The top bar and the title are fixed to the screen rather than sticky: Safari
   drops sticky elements while the page rubber-bands past its end. The page
   leaves room for them (the title's height is measured by the page's script). */
.detail-page {
    padding-top: calc(64px + var(--title-h, 24px));
}

/* "<" stays at the top while the page scrolls beneath it. */
.detail-top {
    position: fixed;
    top: 0;
    left: 50%;
    z-index: 5;
    width: min(100%, var(--col));
    height: 64px;
    padding: 16px var(--gutter) 0;
    transform: translateX(-50%);
    background: linear-gradient(to bottom, var(--bg) 70%, var(--bg-clear));
    pointer-events: none;
}

.back {
    display: block;
    width: 32px;
    height: 32px;
    pointer-events: auto;
    -webkit-tap-highlight-color: transparent;
}

.back:focus-visible {
    outline: 1px solid currentColor;
    outline-offset: 4px;
    border-radius: 50%;
}

.back-dots {
    display: block;
    fill: currentColor;
    overflow: visible;
}

/* The dots land one by one as the page arrives. */
.back-dots circle {
    transform-box: fill-box;
    transform-origin: center;
    animation: dot-in 0.32s var(--spin) both;
}

.back-dots circle:nth-child(1) { animation-delay: 0.38s; }
.back-dots circle:nth-child(2) { animation-delay: 0.52s; }
.back-dots circle:nth-child(3) { animation-delay: 0.66s; }

@keyframes dot-in {
    from { transform: scale(0); }
}

.detail-page .lede {
    min-height: 0;
}

/* The title starts under the bar, rides up with the page, and settles beside
   "<" at body size. --y is its distance from the top of the screen, --t runs
   0 → 1 over the last stretch; both are set by the page's script. */
.detail-page > .lede {
    position: fixed;
    top: 0;
    left: calc(50% - min(50vw, var(--col) / 2) + var(--gutter));
    z-index: 6;
    width: calc(min(100vw, var(--col)) - var(--gutter) * 2);
    transform-origin: left top;
    transform: translate(calc(var(--t, 0) * 44px), var(--y, 64px)) scale(calc(1 - var(--t, 0) * 0.3));
    pointer-events: none;
}

/* Once settled, a long title keeps to one line. */
.detail-page > .lede.is-docked {
    width: calc((min(100vw, var(--col)) - var(--gutter) * 2 - 44px) / 0.7);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Pages slide sideways between the landing (left) and its detail pages (right).
   Uses cross-document view transitions; other browsers just navigate. */
@view-transition {
    navigation: auto;
}

::view-transition-old(root),
::view-transition-new(root) {
    animation-duration: 0.46s;
    animation-timing-function: cubic-bezier(0.55, 0, 0.1, 1);
    animation-fill-mode: both;
}

html.is-detail::view-transition-old(root) { animation-name: slide-out-left; }
html.is-detail::view-transition-new(root) { animation-name: slide-in-right; }
html:not(.is-detail)::view-transition-old(root) { animation-name: slide-out-right; }
html:not(.is-detail)::view-transition-new(root) { animation-name: slide-in-left; }

@keyframes slide-out-left { to { transform: translateX(-100%); } }
@keyframes slide-in-right { from { transform: translateX(100%); } }
@keyframes slide-out-right { to { transform: translateX(100%); } }
@keyframes slide-in-left { from { transform: translateX(-100%); } }

@media (prefers-reduced-motion: reduce) {
    @view-transition {
        navigation: none;
    }

    .back-dots circle,
    .view.is-arrived .pager-dots circle {
        animation: none;
    }
}

.prose {
    margin-top: 56px;
    padding-bottom: 36px;
    line-height: 1.3;
}

.prose > * + * {
    margin-top: 1.3em;
}

.prose h2,
.prose h3 {
    font-size: 14px;
    font-weight: 700;
    line-height: 1.3;
    margin-top: 3em;
}

.prose > :first-child {
    margin-top: 0;
}

.prose h2 + *,
.prose h3 + * {
    margin-top: 0.75em;
}

.prose a {
    text-decoration: underline;
    text-decoration-skip-ink: none;
    text-underline-position: from-font;
}

.prose strong {
    font-weight: 700;
}

.prose ul,
.prose ol {
    list-style: none;
}

.prose li {
    position: relative;
    padding-left: 1.2em;
}

.prose ul > li::before {
    content: '+';
    position: absolute;
    left: 0;
}

.prose ol {
    counter-reset: n;
}

.prose ol > li::before {
    counter-increment: n;
    content: counter(n);
    position: absolute;
    left: 0;
}

.prose blockquote {
    font-size: 20px;
    line-height: 1.2;
    letter-spacing: -0.6px;
}

.prose img,
.prose video {
    display: block;
    width: 100%;
    height: auto;
}

.prose hr {
    border: 0;
    height: 1.5em;
}

/* ---------- Wider screens ---------- */

@media (min-width: 768px) {
    :root {
        --gutter: 24px;
        --col: 450px;
    }

    .page {
        max-width: 450px;
    }
}

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