/* The Logbook — the entry index (/logbook) and the per-entry page
   (/logbook/<slug>). The file keeps its `news.css` name (and `article-*` its
   class names) on purpose: every entry page already baked into S3 links this
   stylesheet by name and carries those classes, so renaming either would strip
   the styling off the live pages until each entry was re-published.

   Both were the last surfaces still running the vocabulary the home page and
   the gallery index retired. The index was a blog roll: hairline-separated
   rows, a 160px cover cropped to 3:2, boxed in a border and desaturated 15%,
   with an uppercase gold "READ MORE →" under an excerpt inside a card that was
   already entirely a link — on a page 1440px wide whose content stopped at
   900px. The article page put six 2048px photographs into a 736px column and
   hung the whole thing against the left margin of a 1200px page.

   Three rules here, and they are the same three the other two redesigns landed
   on. Photographs get the width. Gold marks one thing per page. Structure comes
   from scale and space, not from borders.

   The `ar-` prefix is the Logbook; it covers both pages, which share this file. */

:root {
  /* The warm text ramp, as on the gallery index: base.css's --color-muted
     (#888) is a *cold* grey and reads as a different material against #0c0b08.
     These are the site's own text colour at four weights.
     --ar-body sits below full strength deliberately — #f0ead8 at 100% is a
     poster colour, and these articles run to 5000 words. */
  --ar-body: rgba(240, 234, 216, 0.87);
  --ar-t2: rgba(240, 234, 216, 0.94);   /* titles */
  --ar-t3: rgba(240, 234, 216, 0.56);   /* dates, captions, metadata */
  --ar-t4: rgba(240, 234, 216, 0.32);   /* separators, faint labels */

  /* The reading measure, and the width a photograph is allowed. Text is set
     against the left margin and figures run past it to the full width — an
     asymmetric column rather than a centred one, which is what every other
     page header on this site already does. */
  --ar-measure: 46rem;
  --ar-wide: 62rem;
  --ar-flow: 1.4rem;                    /* the paragraph rhythm */
  --ar-ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* ── Page layout ─────────────────────────────────────────── */

main {
  padding-top: calc(var(--nav-height) + 4rem);
  padding-bottom: 7rem;
  max-width: 1240px;
  margin: 0 auto;
  padding-left: 2.5rem;
  padding-right: 2.5rem;
}

.page-header {
  margin-bottom: 4rem;
}

.page-label {
  font-size: 0.7rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--color-accent);
  margin-bottom: 1rem;
}

.page-title {
  font-family: var(--font-display);
  font-size: clamp(2rem, 4.5vw, 3.5rem);
  font-weight: 400;
  letter-spacing: 0.01em;
  line-height: 1.1;
}

.page-desc {
  margin-top: 1rem;
  font-size: 0.9rem;
  line-height: 1.75;
  color: var(--ar-t3);
  max-width: 34rem;
  letter-spacing: 0.02em;
}

/* ── The index ───────────────────────────────────────────────
   One column of entries, the photograph on the left because the photograph is
   the reason to open the article. No row rules and no card borders: the
   entries are three rem apart and that is separation enough — the hairlines
   were the same instinct that put a box around every gallery cover. */

.news-list {
  display: flex;
  flex-direction: column;
  gap: 3.75rem;
}

.news-card {
  display: grid;
  /* One column width for every entry, lead included: the photographs stack on
     one left edge and the type on another, so the page has a spine. Ranking the
     lead by *also* widening its cover gave the two entries two different text
     margins, which read as a layout that had come apart. */
  grid-template-columns: 26rem minmax(0, 1fr);
  /* Centred, not top-aligned: the entry is a horizontal band of a photograph
     and three lines of type, and hanging the type off the top of a 400px frame
     left a column of nothing under it. */
  align-items: center;
  column-gap: 2.25rem;
  text-decoration: none;
  color: inherit;
}

/* The newest article leads the page, and scale is the whole of the treatment —
   a title at display size over a fuller excerpt. No badge, no "featured" label,
   nothing that has to be explained. Same move as the gallery index's lead
   entry, for the same reason. */
.news-card--lead {
  margin-bottom: 1.25rem;
}

.news-card-text {
  min-width: 0;
}

/* The cover, at last big enough to be a photograph — and shown at its own
   shape. The border, the 15% grayscale, the 160px and the forced 3:2 all went
   with the card: three of them were decoration and the fourth was cropping a
   16:9 air-to-air frame to fit a box. The frame's aspect is set inline from the
   index's `cover_ar` so nothing reflows on load; `overflow: hidden` and the
   `object-fit` keep a stale aspect from letterboxing. */
.news-card-cover {
  position: relative;
  overflow: hidden;
  background: var(--color-surface);
  /* `auto` leaves the height to the image, which is the right degradation for
     an index generated before `cover_ar` existed. */
  aspect-ratio: var(--cover-ar, auto);
}

.news-card-cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  opacity: 0;
  transition: opacity 0.5s ease, filter 0.35s ease;
}

.news-card-cover img.loaded {
  opacity: 1;
}

/* A lift, not a zoom — the strip on the gallery index behaves the same way. */
.news-card:hover .news-card-cover img,
.news-card:focus-visible .news-card-cover img {
  filter: brightness(1.09);
}

.news-card:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 6px;
}

.news-card-date {
  display: block;
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ar-t3);
}

.news-card-title {
  margin: 0.55rem 0 0.65rem;
  font-family: var(--font-display);
  font-size: 1.45rem;
  font-weight: 400;
  line-height: 1.22;
  color: var(--ar-t2);
  text-wrap: balance;
  transition: color 0.25s;
}

.news-card--lead .news-card-title {
  font-size: clamp(1.7rem, 2.6vw, 2.3rem);
  margin-top: 0.7rem;
}

.news-card:hover .news-card-title,
.news-card:focus-visible .news-card-title {
  color: var(--color-accent);
}

.news-card-excerpt {
  margin: 0;
  max-width: 34rem;
  color: var(--ar-t3);
  line-height: 1.7;
  font-size: 0.92rem;
  text-wrap: pretty;
}

.news-card--lead .news-card-excerpt {
  font-size: 1rem;
  color: var(--ar-body);
}

/* No "Read more". The whole entry is the link, the title lights up under the
   cursor, and an uppercase gold CTA on every row spent the page's one accent
   colour on an affordance that was already there. */

.empty-state {
  padding: 4rem 0;
  color: var(--ar-t3);
  font-size: 0.9rem;
  letter-spacing: 0.05em;
}

/* ── The article ─────────────────────────────────────────────
   Text against the left margin at a reading measure; photographs run past it
   to the full width. The column is asymmetric on purpose: a 736px strip
   centred-ish in a 1200px page reads as a page that failed to fill, while a
   deliberate left column with the images breaking out of it reads as a page
   that was set. */

/* The block is centred in the page; the *text inside it* stays against its left
   edge. Left-aligning the block as well left the photographs' right edge 340px
   short of a margin that was 176px on the other side, which reads as a page
   that ran out rather than one that was set. */
.article {
  max-width: var(--ar-wide);
  margin-inline: auto;
}

/* The linked gallery's cover, baked into the article HTML. Full width of the
   article, and a band rather than a 16:9 picture — at 16:9 it stood 630px tall
   and pushed the article's own title past the fold, so a reader arrived at a
   photograph with no idea what they had opened. Capped by viewport height as
   well as by aspect, so a short window doesn't open on nothing but banner. */
.article-hero {
  position: relative;
  width: 100%;
  aspect-ratio: 21 / 9;
  max-height: 54vh;
  background-size: cover;
  background-position: center;
}

.article-hero::after {
  content: "";
  position: absolute;
  inset: 0;
  /* Reaching the page colour well before the bottom edge is what removes the
     edge: the last sixth of the band is already background, which is where the
     header sits. A fade that finishes at 98% leaves a bright strip meeting
     black in a straight line. */
  background: linear-gradient(to bottom,
    transparent 25%, rgba(12, 11, 8, 0.6) 62%, var(--color-bg) 85%);
}

/* The header runs up into the bottom of that fade, which is what ties the two
   together — a banner with a gap under it is a banner the page is merely
   sitting below. `position: relative` puts the type over the gradient; the
   gradient is at the page's own background colour by then, so nothing is
   reversed out of a photograph. */
.article-hero + .page-header {
  margin-top: -3.75rem;
  position: relative;
}

.article .page-header {
  max-width: var(--ar-measure);
  margin-bottom: 3rem;
}

/* A hero belongs against the nav; the 4rem of air is for a page that opens on
   a text header instead. */
main:has(.article-hero) {
  padding-top: calc(var(--nav-height) + 1.75rem);
}

/* Muted, not gold. The header used to carry three gold items (this, the date
   and the gallery link) which between them ranked nothing; the accent is spent
   on the gallery link alone now. */
.article-back {
  display: inline-block;
  margin-bottom: 1.75rem;
  text-decoration: none;
  font-size: 0.7rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ar-t3);
  transition: color 0.2s;
}

.article-back:hover {
  color: var(--color-accent);
}

.article .page-title {
  text-wrap: balance;
}

.article .page-meta {
  margin-top: 1.25rem;
  font-size: 0.75rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ar-t3);
}

.article-gallery {
  display: inline-block;
  margin-top: 1.1rem;
  font-size: 0.8rem;
  letter-spacing: 0.05em;
  color: var(--color-accent);
  text-decoration: none;
  border-bottom: 1px solid rgba(232, 168, 0, 0.4);
  padding-bottom: 2px;
  transition: border-color 0.2s;
}

.article-gallery:hover {
  border-color: var(--color-accent);
}

/* ── The prose ───────────────────────────────────────────────
   The body is Markdown output, so every rule here has to work off bare
   elements — there are no classes to hang anything on and there should not be.

   The grid is what gives a figure its width: ordinary flow lands in the `text`
   column, a standalone image spans `wide`. Grid rather than block also means
   margins no longer collapse, so the rhythm is a single `row-gap` and the
   children carry no bottom margins at all. */

.article-body {
  display: grid;
  grid-template-columns:
    [text-start wide-start] min(100%, var(--ar-measure)) [text-end]
    minmax(0, 1fr) [wide-end];
  row-gap: var(--ar-flow);
  font-size: 1.0625rem;
  line-height: 1.75;
  color: var(--ar-body);
}

/* Both languages are baked into the page and js/article.js hides one with the
   `hidden` attribute — which is a *UA* rule (`[hidden] { display: none }`) and
   therefore loses to any author `display` declaration. Without this the article
   rendered twice, Polish then English. */
.article-body[hidden] {
  display: none;
}

.article-body > * {
  grid-column: text;
  min-width: 0;
  margin: 0;
}

.article-body p {
  text-wrap: pretty;
}

/* The opening paragraph, set larger. Free structure: Markdown always gives the
   article an opening paragraph, and a lede is what tells a reader the piece has
   been edited rather than merely posted. */
.article-body > p:first-child {
  font-size: 1.2rem;
  line-height: 1.6;
  color: var(--ar-t2);
  margin-bottom: 0.5rem;
}

/* Author headings. These articles are written with `#`, so the body carries
   real <h1>s — which had no rule at all and were rendering at the browser
   default: 2em bold Montserrat, directly under a page title in DM Serif. Two
   typographic systems on one page, and the single loudest reason the article
   looked unfinished. All four levels are set, in the display face, and the
   sizes step rather than restarting the scale. */
.article-body :is(h1, h2, h3, h4) {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: 0.01em;
  color: var(--ar-t2);
  margin-top: 1.9rem;
  text-wrap: balance;
}

.article-body h1 { font-size: 1.85rem; }
.article-body h2 { font-size: 1.55rem; }
.article-body h3 { font-size: 1.25rem; }
.article-body h4 { font-size: 1.05rem; }

/* A heading opening the piece needs no run-in space above it. */
.article-body > :is(h1, h2, h3, h4):first-child {
  margin-top: 0;
}

.article-body a {
  color: var(--color-accent);
  text-decoration: none;
  border-bottom: 1px solid rgba(232, 168, 0, 0.4);
  transition: border-color 0.2s;
}

.article-body a:hover {
  border-color: var(--color-accent);
}

.article-body :is(ul, ol) {
  padding-left: 1.35rem;
}

.article-body li {
  margin-bottom: 0.45rem;
}

.article-body li::marker {
  color: var(--ar-t4);
}

/* ── Figures ─────────────────────────────────────────────────
   Both shapes Markdown can produce: `![alt](src "Caption")` is rewrapped as a
   <figure> by the renderer, a captionless image stays a lone <p><img></p>.
   Both take the full width, and neither is framed — a hairline around a
   photograph is the thing the gallery redesign retired. */

.article-body > figure,
.article-body > p:has(> img:only-child) {
  grid-column: wide;
  margin-top: 1.6rem;
  margin-bottom: 1.6rem;
}

/* A landscape frame takes the whole width; a *portrait* one is bounded by
   height instead, because 1120px wide would make it 1600px tall and turn one
   photograph into two screens of scrolling. Neither is ever upscaled — an
   attachment smaller than the column keeps its own size rather than being
   stretched to fill one. */
.article-body img {
  max-width: 100%;
  max-height: 84vh;
  width: auto;
  height: auto;
  display: block;
  background: var(--color-surface);
}

/* The fade is opt-in from js/article.js, which adds the class as it wires the
   load handlers. Starting the images at zero in CSS would leave a reader with
   JS off looking at six blank frames. */
.article-body--fade img {
  opacity: 0;
  transition: opacity 0.6s ease;
}

.article-body--fade img.loaded {
  opacity: 1;
}

/* The caption is set to the reading measure and left-aligned under the frame,
   not centred under a 1120px photograph where it would float in the middle of
   nothing. */
.article-body figcaption {
  margin-top: 0.7rem;
  max-width: var(--ar-measure);
  font-size: 0.8rem;
  line-height: 1.5;
  letter-spacing: 0.04em;
  color: var(--ar-t3);
}

/* ── The rest of what Markdown can emit ──────────────────── */

.article-body blockquote {
  margin-top: 0.6rem;
  margin-bottom: 0.6rem;
  padding-left: 1.4rem;
  border-left: 1px solid var(--color-accent);
  font-family: var(--font-display);
  font-size: 1.2rem;
  line-height: 1.5;
  color: var(--ar-t2);
}

.article-body blockquote p {
  margin: 0;
}

.article-body hr {
  border: 0;
  border-top: 1px solid var(--color-border);
  margin-top: 1.6rem;
  margin-bottom: 1.6rem;
}

.article-body code {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  padding: 0.1em 0.35em;
  font-size: 0.88em;
}

.article-body pre {
  grid-column: wide;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  padding: 1rem 1.25rem;
  overflow-x: auto;
}

.article-body pre code {
  background: none;
  border: none;
  padding: 0;
}

.article-body table {
  border-collapse: collapse;
  font-size: 0.9rem;
}

.article-body :is(th, td) {
  padding: 0.5rem 0.9rem 0.5rem 0;
  text-align: left;
  border-bottom: 1px solid var(--color-border);
}

.article-body th {
  color: var(--ar-t3);
  font-weight: 400;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-size: 0.72rem;
}

/* ── Where the reader goes next ──────────────────────────────
   Built by js/article.js from what is already in the page, because the article
   HTML is baked and a markup change would only reach articles republished
   after it. Before this the piece simply stopped: 5000 words, six
   photographs, and then the footer. */

.article-foot {
  max-width: var(--ar-wide);
  margin-inline: auto;
  margin-top: 4.5rem;
  padding-top: 2.5rem;
  border-top: 1px solid var(--color-border);
}

.article-foot-gallery {
  display: grid;
  grid-template-columns: 15rem minmax(0, 1fr);
  align-items: center;
  column-gap: 2rem;
  text-decoration: none;
  color: inherit;
}

.article-foot-gallery--bare {
  grid-template-columns: minmax(0, 1fr);
}

.article-foot-cover {
  aspect-ratio: 3 / 2;
  background: var(--color-surface) center / cover no-repeat;
  transition: filter 0.35s ease;
}

.article-foot-gallery:hover .article-foot-cover {
  filter: brightness(1.09);
}

.article-foot-label {
  display: block;
  font-size: 0.7rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ar-t3);
}

.article-foot-cta {
  display: block;
  margin-top: 0.5rem;
  font-family: var(--font-display);
  font-size: 1.4rem;
  line-height: 1.25;
  color: var(--ar-t2);
  transition: color 0.25s;
}

.article-foot-gallery:hover .article-foot-cta {
  color: var(--color-accent);
}

.article-foot-back {
  display: inline-block;
  margin-top: 2.5rem;
  font-size: 0.7rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ar-t3);
  text-decoration: none;
  transition: color 0.2s;
}

.article-foot-back:hover {
  color: var(--color-accent);
}

/* ── Narrow ──────────────────────────────────────────────────
   The index stacks cover-over-text (the photograph still leads), and the
   article's two columns collapse into one — which is what the grid's
   `min(100%, …)` was for. */

@media (max-width: 860px) {
  main {
    padding-left: 1.5rem;
    padding-right: 1.5rem;
  }

  .page-header {
    margin-bottom: 3rem;
  }

  .news-list {
    gap: 3rem;
  }

  .news-card,
  .news-card--lead {
    grid-template-columns: 1fr;
    row-gap: 1.1rem;
  }

  .news-card-text {
    padding-top: 0;
  }

  /* A 21:9 band across a 390px phone is 167px of photograph, a third of which
     the fade takes — so the band gets taller as the column gets narrower, and
     the header's run-in shortens with it. */
  .article-hero {
    aspect-ratio: 4 / 3;
    max-height: 46vh;
  }

  .article-hero + .page-header {
    margin-top: -2.75rem;
  }

  .article-body {
    font-size: 1rem;
  }

  .article-body > p:first-child {
    font-size: 1.1rem;
  }

  .article-foot-gallery {
    grid-template-columns: 1fr;
    row-gap: 1rem;
  }
}
