/* site-odenir — "preto espacial" palette (spec §1).
   Neutrals carry no hue. Color is information: --live means Spotify, the
   --ogs-* trio means OGS. Neither appears outside its role. */
:root {
  --bg: #1D1D1F;
  --surface: #2A2A2D;
  --line: #3A3A3D;
  --fg: #F5F5F7;
  --soft: #A1A1A6;
  --live: #1ED760;
  --ogs-bg: #302F76;
  --ogs-cta: #E39C19;
  --ogs-fg: #F0F2FE;

  /* Type scale: five sizes, one job each, ~1.25x apart. */
  --fs-label: .8125rem;  /* 13px: every mono readout */
  --fs-body: 1rem;       /* 16px: text, links, secondary lines */
  --fs-title: 1.25rem;   /* 20px: item and pinned titles */
  --fs-value: 1.5rem;    /* 24px: panel numbers */
  --fs-name: 2rem;       /* 32px: the name */

  --sans: 'Sora', system-ui, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, monospace;
  --bar-h: 64px;
  --ease-out: cubic-bezier(.2, .6, .2, 1); /* quick start, long settle: state changes */
  color-scheme: dark;
}

*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }

/* The page color sits on <html> so the chronovisor (z-index -1) can show
   between it and the body. */
html { -webkit-text-size-adjust: 100%; background: var(--bg); }
body {
  margin: 0;
  color: var(--fg);
  font: 400 var(--fs-body)/1.55 var(--sans);
}
a { color: inherit; }
h1, h2, h3, p { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
img { display: block; max-width: 100%; height: auto; }
button { font: inherit; color: inherit; }

:focus-visible { outline: 2px solid var(--fg); outline-offset: 2px; }

.mono, .lang, .label, .src, .meta, .tag, .end, .site-footer h2, .credit { font-family: var(--mono); font-weight: 400; }

/* ── Chronovisor ── the feed card in the middle of the screen projects its
   image behind the whole page, soft and a little drained. Each new image
   fades in over the last one, settling from a slightly closer zoom (app.js), and app.js sets each image's own --chrono-brightness:
   the brightest it can be before the page text stops reading. */
.chrono {
  --chrono-blur: 16px;      /* above the ~8px where a 200px image shows its pixels */
  --chrono-saturate: .8;
  --chrono-veil: 30%;
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}
.chrono img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: blur(var(--chrono-blur)) saturate(var(--chrono-saturate)) brightness(var(--chrono-brightness, .5));
  transform: scale(1.2);
  opacity: 0;
  transition: opacity .8s var(--ease-out), transform 1.6s var(--ease-out);
  will-change: opacity, transform; /* own layer: the blur is painted once, not per frame */
}
.chrono img.is-tall { object-position: 50% 30%; } /* reels: keep the face, not the chest */
.chrono img.is-on { opacity: 1; transform: scale(1.15); } /* pushes the blur's soft edge off screen */
.chrono::after { content: ''; position: absolute; inset: 0; background: color-mix(in srgb, var(--bg) var(--chrono-veil), transparent); }

/* With a memory on, small and muted text sits on a halo of --bg: grey and
   moss fall under 4.5:1 over the brightest part of an image without it. */
.has-memory :is(.meta, .sub, .tag, .hero p, .hero summary, .hero .label, .entry p) {
  text-shadow: 0 0 2px var(--bg), 0 0 6px var(--bg), 0 0 12px var(--bg);
}

/* The hero photo and the pinned cards already have an edge: as the memory,
   it lights up instead. */
.hero__photo, .pinned { transition: border-color .35s var(--ease-out); }
.hero.is-memory .hero__photo, .pinned.is-memory { border-color: var(--soft); }
.pinned--ogs.is-memory { border-color: var(--ogs-fg); }

/* ── Layout ───────────────────────────────────────────────────────── */

.page {
  max-width: 600px;
  margin: 0 auto;
  padding: 0 16px 48px;
  position: relative;
}
.main { display: grid; gap: 24px; min-width: 0; scroll-margin-top: calc(var(--bar-h) + 24px); }
@media (min-width: 960px) {
  .page { max-width: 664px; padding-bottom: 64px; }
}

/* ── 0. Top bar ─────────────────────────────────────────────────── */
/* Phones: mark and language on the first row, the sections scroll sideways
   on the second. From 960px one row, its edges flush with the 1024px grid. */

.topbar {
  position: sticky;
  top: 0;
  z-index: 5;
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas: "mark lang" "sections sections";
  align-items: center;
  gap: 8px 16px;
  padding: 12px 16px 8px;
  border-bottom: 1px solid var(--line);
  background: rgb(30 38 40 / .88);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}
.mark { display: flex; align-items: center; gap: 10px; color: var(--fg); text-decoration: none; }
.mark img { flex: none; width: 40px; height: 40px; border-radius: 50%; border: 2px solid var(--fg); object-fit: cover; }
.mark b { display: block; font-size: .9375rem; line-height: 1.2; letter-spacing: -.01em; white-space: nowrap; }
.mark small { display: block; font-family: var(--mono); font-size: var(--fs-label); line-height: 1.4; color: var(--soft); white-space: nowrap; }
.topbar .mark { grid-area: mark; justify-self: start; }
.sections {
  grid-area: sections;
  display: flex;
  gap: 4px;
  margin: 0 -16px;
  padding: 0 16px;
  overflow-x: auto;
  scrollbar-width: none;
}
.sections::-webkit-scrollbar { display: none; }
.filters { display: flex; gap: 4px; }
.filters button, .pl-link {
  flex: none;
  padding: 6px 12px;
  border: 0;
  border-radius: 6px;
  background: none;
  color: var(--soft);
  font-size: .9375rem;
  line-height: 1.5;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}
.filters button:hover, .pl-link:hover { color: var(--fg); background: var(--surface); }
.filters button[aria-pressed="true"] { color: var(--bg); background: var(--fg); }
@media (min-width: 960px) {
  .topbar {
    height: var(--bar-h);
    grid-template-columns: auto 1fr auto;
    grid-template-areas: "mark sections lang";
    gap: 24px;
    padding: 0 max(16px, (100% - 1024px) / 2);
  }
  .sections { justify-self: end; margin: 0; padding: 0; overflow: visible; }
  .lang { padding-left: 24px; border-left: 1px solid var(--line); }
}

/* The current language is a filled segment; the other one is the link. */
.lang { grid-area: lang; display: inline-flex; font-size: var(--fs-label); }
.lang a, .lang [aria-current] { padding: 5px 12px; border-radius: 999px; line-height: 1.4; }
.lang a { color: var(--soft); text-decoration: none; }
.lang a:hover { color: var(--fg); }
.lang [aria-current] { background: var(--fg); color: var(--bg); }

/* ── 1–2. Hero ──────────────────────────────────────────────────── */
/* Full width, the first screen minus PEEK: the pinned post shows below it,
   so the page reads as "there is more" before the cue says so. Phones stack
   the photo over the text; from 960px they sit side by side on the bar's
   1024px grid. */

.hero {
  --peek: 96px;
  position: relative;
  display: grid;
  gap: 24px;
  align-content: center;
  min-height: calc(100svh - var(--bar-h) - var(--peek));
  max-width: 1024px;
  margin: 0 auto 32px;
  padding: 32px 16px 72px;
}
.hero__text { display: grid; gap: 16px; justify-items: start; min-width: 0; }
.hero__label {
  font: 400 .6875rem/1 var(--mono);
  color: var(--soft);
  text-transform: uppercase;
  letter-spacing: .14em;
}
.hero h1 { font-weight: 700; font-size: var(--fs-name); line-height: 1.05; letter-spacing: -.03em; }
.hero__photo {
  order: -1;
  width: 120px;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface);
}
@media (min-width: 960px) {
  .hero {
    grid-template-columns: minmax(0, 1fr) 320px;
    gap: 64px;
    align-items: center;
    padding-inline: 0;
  }
  .hero h1 { font-size: 3.5rem; }
  .hero__text { max-width: 560px; }
  .hero__photo { order: 0; width: 100%; }
}

/* The cue: a link to the feed with a bobbing arrow. It fades once the
   visitor has scrolled (app.js sets .is-scrolled), and holds still under
   reduced motion. */
.cue {
  position: absolute;
  left: 50%;
  bottom: 16px;
  transform: translateX(-50%);
  display: grid;
  justify-items: center;
  font: 400 var(--fs-label)/1 var(--mono);
  letter-spacing: .1em;
  color: var(--soft);
  text-decoration: none;
  transition: opacity .3s ease;
}
.cue::after { content: '↓'; font-size: 1.125rem; animation: bob 1.6s ease-in-out infinite; }
.cue:hover { color: var(--fg); }
@keyframes bob { 50% { transform: translateY(5px); opacity: .5; } }
.is-scrolled .cue { opacity: 0; pointer-events: none; }
/* Phones: the hero outgrows the first screen, so neither the peek nor the
   cue would show; the cue pins to the screen's bottom on a plate instead. */
@media (max-width: 959px) {
  .cue {
    position: fixed;
    z-index: 4;
    bottom: 16px;
    grid-auto-flow: column;
    gap: 6px;
    align-items: center;
    padding: 8px 14px;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: color-mix(in srgb, var(--bg) 88%, transparent);
  }
  .cue::after { font-size: 1rem; }
}

.bio { max-width: 52ch; color: var(--soft); font-size: 1.0625rem; }
.bio summary { cursor: pointer; list-style: none; }
.bio summary::-webkit-details-marker { display: none; }
.bio summary:hover .more { color: var(--fg); }
.more { font-family: var(--mono); font-size: var(--fs-label); color: var(--soft); text-decoration: underline; white-space: nowrap; }
.more::after { content: ' +'; }
.bio[open] .more { display: none; }
.bio > p { margin-top: 6px; }

/* Links: icon buttons, each a 44px target; name and handle in the label. */
.links { display: flex; gap: 4px; margin-left: -12px; }
.links a {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 6px;
  color: var(--soft);
}
.links a:hover { color: var(--fg); background: var(--surface); }
.vh { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.icon { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }

/* ── 3. Readout panel ─────────────────────────────────────────────── */

/* Readouts side by side: the label above, the number and its unit below. */
.nums { display: flex; flex-wrap: wrap; gap: 12px 40px; margin: 8px 0 0; }
.nums dd { margin: 4px 0 0; }
.label { font-size: var(--fs-label); color: var(--soft); }
.value { font-weight: 700; font-size: var(--fs-value); line-height: 1.1; letter-spacing: -.02em; overflow-wrap: anywhere; }
.src { font-size: var(--fs-label); color: var(--soft); }
.off { color: var(--ogs-cta); }

/* Spotify bar: data-state is idle (nothing loaded), playing or paused.
   Only "playing" turns it green and moves the equalizer. */
.np {
  display: grid;
  grid-template-columns: 22px minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  min-width: min(100%, 300px);
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 12px;
  text-decoration: none;
}
.np:hover { background: var(--surface); }
.np__text { display: grid; min-width: 0; line-height: 1.35; }
.np__text strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.np__sub { font-family: var(--mono); font-size: var(--fs-label); color: var(--soft); }
.np .src { color: var(--live); }
.np[data-state="playing"] { border-color: color-mix(in srgb, var(--live) 45%, var(--line)); }
.np[data-state="playing"] strong { color: var(--live); }

.np__icon { display: flex; align-items: end; justify-content: center; gap: 2px; width: 22px; height: 22px; }
.np__icon i { width: 3px; height: 30%; border-radius: 1px; background: var(--live); }
.np[data-state="playing"] .np__icon i { animation: eq 1s ease-in-out infinite alternate; }
.np__icon i:nth-child(2) { animation-delay: -.3s; }
.np__icon i:nth-child(3) { animation-delay: -.6s; }
@keyframes eq { from { height: 100%; } to { height: 20%; } }

/* Idle: the icon is a play button instead of bars. */
.np[data-state="idle"] .np__icon { align-items: center; border-radius: 50%; background: var(--live); }
.np[data-state="idle"] .np__icon i { display: none; }
.np[data-state="idle"] .np__icon::after {
  content: '';
  margin-left: 2px;
  border-left: 7px solid var(--bg);
  border-top: 4.5px solid transparent;
  border-bottom: 4.5px solid transparent;
}

/* ── 5. Pinned posts ──────────────────────────────────────────────── */
/* The --ogs-* trio only on the OGS card; the article keeps the site palette. */

.pinned {
  display: grid;
  gap: 10px;
  padding: 20px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface);
}
.pinned .meta { color: var(--soft); }
.pinned h2 { font-size: var(--fs-title); font-weight: 700; line-height: 1.3; }
.cta {
  justify-self: start;
  margin-top: 4px;
  padding: 10px 18px;
  border-radius: 4px;
  background: var(--fg);
  color: var(--bg);
  font-weight: 600;
  text-decoration: none;
}
.pinned--ogs { border-color: var(--ogs-bg); background: var(--ogs-bg); color: var(--ogs-fg); }
.pinned--ogs .meta { color: var(--ogs-fg); opacity: .75; }
.pinned--ogs .cta { background: var(--ogs-cta); color: var(--ogs-bg); }
.pinned--ogs .cta:focus-visible { outline-color: var(--ogs-fg); }

/* Thumbnail: a square on the right of the text. The log's posts, its
   unlinked entries and the pinned cards share it, so every item with an
   image reads the same way. Where the date sits beside it (pinned cards,
   unlinked entries) the date spans both columns and the square starts under it. */
.post:has(> img), .pinned:has(> img), .entry:has(> img) {
  grid-template-columns: minmax(0, 1fr) 88px;
  column-gap: 16px;
  align-items: start;
}
.post > img, .pinned > img, .entry > img {
  grid-column: 2;
  width: 88px;
  height: 88px;
  object-fit: cover;
  border-radius: 4px;
  background: var(--surface);
}
.post > :not(img), .pinned > :not(img), .entry:has(> img) > :not(img) { grid-column: 1; }
.post > img { grid-row: 1 / span 2; }
.pinned > .meta, .entry:has(> img) > .meta { grid-column: 1 / -1; }
.pinned > img, .entry > img { grid-row: 2 / span 3; }

/* ── 6. Feed as a log ─────────────────────────────────────────────── */

.log { border-left: 1px solid var(--line); margin-left: 4px; }
.entry {
  position: relative;
  display: grid;
  gap: 8px;
  padding: 0 0 32px 22px;
}
.entry::before {
  content: '';
  position: absolute;
  left: -5px;
  top: .45em;
  width: 9px;
  height: 9px;
  background: var(--fg);
}
.meta { font-size: var(--fs-label); color: var(--soft); }
/* The card whose memory is on: a plate of --bg behind it, its marker lit. */
.entry { isolation: isolate; }
.entry::after {
  content: '';
  position: absolute;
  inset: -14px -16px 16px 8px;
  z-index: -1;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  opacity: 0;
  transform: scale(.98);
  transition: opacity .35s var(--ease-out), transform .35s var(--ease-out);
}
.entry::before { transition: background-color .35s var(--ease-out); }
.entry.is-memory::after { opacity: 1; transform: none; }
.entry.is-memory::before { background: var(--fg); }
.entry h3 { font-size: var(--fs-title); font-weight: 600; line-height: 1.3; }
.sub { color: var(--soft); font-size: var(--fs-body); }
a.sub { justify-self: start; }

/* The log's end: a hollow marker on the same rail, then where the record
   starts. The build date is in the site footer. */
.end {
  position: relative;
  display: grid;
  gap: 2px;
  margin: -24px 0 0 5px; /* cancel .main's gap so the marker sits on the rail's end */
  padding-left: 22px;
  font-size: var(--fs-label);
  color: var(--soft);
}
.end::before {
  content: '';
  position: absolute;
  left: -5px;
  top: .45em;
  width: 9px;
  height: 9px;
  border: 1px solid var(--soft);
  background: var(--bg);
}
/* Asks app.js for the next page; sits on the gap, takes no room. */
.more-sentinel { height: 1px; margin-top: -24px; }
a.sub:hover { color: var(--fg); }

.post { display: grid; gap: 10px; text-decoration: none; }
.post:hover h3, .post:hover p { color: var(--soft); }

.stack { display: flex; flex-wrap: wrap; gap: 6px; }
.tag {
  justify-self: start;
  padding: 2px 8px;
  border: 1px solid var(--line);
  border-radius: 3px;
  font-size: var(--fs-label);
  color: var(--soft);
}

/* ── 7. Spotify drawer and bubble ─────────────────────────────────── */

.drawer {
  position: fixed;
  inset: auto 0 0 0;
  width: 100%;
  max-width: 560px;
  max-height: 85vh;
  margin: 0 auto;
  padding: 0 16px 24px;
  border: 0;
  border-top: 2px solid var(--live);
  border-radius: 12px 12px 0 0;
  background: var(--surface);
  color: var(--fg);
  overflow-y: auto;
  opacity: 0;
  transform: translateY(100%);
  transition: transform 200ms ease-out, opacity 200ms ease-out;
}
.drawer.is-open { opacity: 1; transform: none; }
.drawer::backdrop { background: rgb(0 0 0 / .5); }

.drawer__head {
  position: sticky;
  top: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 0 12px;
  background: var(--surface);
}
.drawer__head h2 { font-size: var(--fs-body); font-weight: 600; color: var(--live); }
.drawer__close {
  width: 40px;
  height: 40px;
  border: 0;
  border-radius: 50%;
  background: none;
  font-size: var(--fs-value);
  line-height: 1;
  cursor: pointer;
}
.drawer__close:hover { background: var(--line); }
.drawer__player { margin-bottom: 12px; }
.drawer__player iframe { display: block; width: 100%; border: 0; border-radius: 12px; }
.drawer__hint { margin-top: 8px; font: 400 var(--fs-label)/1.4 var(--mono); color: var(--soft); }
.playlist {
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr);
  align-items: center;
  gap: 8px 12px;
  padding: 10px 0;
  border-top: 1px solid var(--line);
}
.playlist img, .cover { width: 56px; height: 56px; border-radius: 4px; }
.cover { display: grid; place-items: center; background: var(--bg); color: var(--live); }
.pl-title { font-weight: 600; overflow-wrap: anywhere; }
.pl-actions { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 8px; }
.pl-actions button, .pl-actions a {
  min-height: 36px;
  padding: 6px 14px;
  border-radius: 999px;
  font-size: var(--fs-label);
  text-decoration: none;
  cursor: pointer;
}
.pl-actions button { border: 0; background: var(--live); color: var(--bg); font-weight: 600; }
.pl-actions a { display: inline-flex; align-items: center; border: 1px solid var(--line); }
.pl-actions a:hover { border-color: var(--live); }

@media (min-width: 480px) {
  .playlist { grid-template-columns: 56px minmax(0, 1fr) auto; }
  .pl-actions { grid-column: auto; }
}

.bubble {
  position: fixed;
  right: 16px;
  bottom: 16px;
  z-index: 10;
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border: 0;
  border-radius: 50%;
  background: var(--live);
  color: var(--bg);
  box-shadow: 0 4px 16px rgb(0 0 0 / .4);
  cursor: pointer;
}
.bubble svg { width: 24px; height: 24px; fill: currentColor; }
.bubble[data-paused="true"] .i-pause, .bubble:not([data-paused="true"]) .i-play { display: none; }
.bubble:focus-visible { outline-color: var(--fg); outline-offset: 3px; }

/* ── 8. Site footer ───────────────────────────────────────────────── */
/* Full width under the page, its grid flush with the 1024px one. */

.site-footer {
  display: grid;
  gap: 32px;
  padding: 40px max(16px, (100% - 1024px) / 2) 104px; /* clears the bubble */
  border-top: 1px solid var(--line);
  color: var(--soft);
}
.site-footer .cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 32px 24px; }
.site-footer .intro { grid-column: 1 / -1; display: grid; gap: 10px; }
.site-footer .intro p { max-width: 32ch; }
.site-footer .mark { color: var(--fg); }
.site-footer h2 {
  margin-bottom: 10px;
  font-size: .6875rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--soft);
}
.site-footer li { line-height: 2; }
.site-footer a, .site-footer button { color: inherit; text-decoration: none; }
.site-footer button { padding: 0; border: 0; background: none; cursor: pointer; }
.site-footer a:hover, .site-footer button:hover { color: var(--fg); }
.ext::after { content: ' ↗'; font-size: .75em; opacity: .6; }
.credit {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 4px 16px;
  padding-top: 20px;
  border-top: 1px solid var(--line);
  font-size: var(--fs-label);
}
@media (min-width: 720px) {
  .site-footer .cols { grid-template-columns: 1.6fr repeat(3, minmax(0, 1fr)); }
  .site-footer .intro { grid-column: auto; align-content: start; }
}
@media (min-width: 960px) { .site-footer { padding-bottom: 40px; } }

@media (prefers-reduced-motion: reduce) {
  .drawer, .chrono img, .entry::before, .entry::after, .hero__photo, .pinned, .cue { transition: none; }
  .cue::after { animation: none; }
  .np[data-state] .np__icon i { animation: none; }
}
