/* ==========================================================================
   ARTICLES - "Notes from the field"
   index.html § 10 (three cards), articles.html (the archive grid and the
   reader). Rendered by js/articles.js from Firestore; this sheet owns every
   class that file writes. Loaded by those two pages only, on top of either
   css/home-main.css (the home page) or css/main.css (articles.html) - it
   uses only tokens the two sheets share.

   AN INSIGHTS SECTION, NOT A NEWS FRONT. The first version led with the
   newest article at size and ran the rest down a dated index rail; with a
   date, a reading time and a byline on every entry it read like a
   newspaper. This is the business-site cut: a centred head - pill, heading,
   one line of purpose, a quiet link to the rest - over a row of equal
   text cards, each a category, a title, a short summary and "Read more".
   No cover images, here or on the article page. Dates, reading times and
   bylines live on the article page, where a reader who chose the article
   wants them.

   THE CARDS ARE THE SITE'S OWN. The careers cards' surface (a gold wash
   fading into --surface over a hairline border), the soft corner of the
   newer homepage cards (b2b, record), the careers pill for the badge, and
   the house eyebrow - a short gold rule, then tracked capitals - for the
   category at the top of each card.

   THE ROW CENTRES, IT NEVER STRANDS. Flex rather than a fixed grid: three
   to a row on a laptop, two on a tablet, one on a phone, and a short last
   row sits in the middle instead of hugging the left beside empty columns.
   Every card in a row is the same height, and "Read more" sits on the same
   line in all of them.
   ========================================================================== */

/* css/main.css (articles.html) does not define the bar height; this is the
   value css/home-main.css gives it */
.jnl,
.rdr {
  --jnl-nav-h: var(--nav-h, clamp(4.6rem, 4rem + 1.4vw, 5.35rem));
  --jn-r: clamp(0.85rem, 0.6rem + 0.7vw, 1.25rem);  /* the card corner */
  --jn-gap: clamp(1.25rem, 0.9rem + 1.2vw, 2rem);
}

.jnl { scroll-margin-top: var(--jnl-nav-h); }

/* ---- the head: centred, the careers page's pill over the heading ------- */

.jnl__head {
  display: flex;
  flex-direction: column;
  align-items: center;
  max-width: 44rem;
  margin: 0 auto clamp(2.25rem, 1.6rem + 2.4vw, 4rem);
  text-align: center;
}
.jnl__badge {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: clamp(1rem, 0.85rem + 0.6vw, 1.5rem);
  padding: 0.42rem 0.95rem;
  border: 1px solid var(--border-gold);
  border-radius: 999px;
  background: var(--gold-wash);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold-light);
}
.jnl__h {
  max-width: 18ch;
  font-size: clamp(1.75rem, 1.3rem + 2.2vw, 2.9rem);
  letter-spacing: -0.032em;
  line-height: 1.06;
}
.jnl__h em { font-style: italic; color: var(--gold-light); }
.jnl__sub {
  margin-top: 0.9rem;
  max-width: 38rem;
  color: var(--vein);
  line-height: 1.7;
  text-wrap: pretty;
}
.jnl__all { margin-top: clamp(1rem, 0.8rem + 0.8vw, 1.5rem); }
.jnl__all[hidden] { display: none; }
.jnl__all .link-line svg { transition: transform 0.35s var(--ease-out); }

/* ---- the row of cards ---------------------------------------------------- */

.jnl__grid {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--jn-gap);
}
/* each cell is a flex box so the card inside fills it: one height per row */
.jnl__grid > li {
  display: flex;
  flex: 0 1 100%;
  min-width: 0;
}
@media (min-width: 640px) {
  .jnl__grid > li { flex-basis: calc((100% - var(--jn-gap)) / 2); }
}
@media (min-width: 1024px) {
  .jnl__grid > li { flex-basis: calc((100% - 2 * var(--jn-gap)) / 3); }
}

/* ==========================================================================
   .jn - one card: category, title, summary, "Read more"
   ========================================================================== */

.jn {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  min-width: 0;
  /* a lone card, or one with a short summary, still reads as a card */
  min-height: clamp(14rem, 12rem + 4vw, 16.5rem);
  border: 1px solid var(--border-neutral);
  border-radius: var(--jn-r);
  background: linear-gradient(180deg, rgba(184, 145, 88, 0.05), transparent 46%), var(--surface);
  box-shadow: var(--shadow-card);
  transition: border-color 0.35s ease, transform 0.16s ease-out;
}

.jn__body {
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: 0.75rem;
  min-width: 0;
  padding: clamp(1.5rem, 1.2rem + 0.9vw, 2.1rem);
}

/* the category: the house eyebrow in small - a short gold rule, then the
   word in tracked capitals. It is the card's only ornament. */
.jn__label {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  margin-bottom: 0.15rem;
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.18em;
  line-height: 1.4;
  text-transform: uppercase;
  color: var(--gold);
  overflow-wrap: anywhere;
}
.jn__label::before {
  content: "";
  flex: none;
  width: 1.5rem;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--gold));
}

.jn__title {
  font-size: clamp(1.2rem, 1.05rem + 0.55vw, 1.45rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.3;
  color: var(--white);
  overflow-wrap: anywhere;
  hyphens: auto;
  text-wrap: pretty;
  transition: color 0.35s ease;
}

/* THE TITLE IS THE ONE LINK, AND IT COVERS THE CARD. The stretch resolves
   against .jn, the nearest positioned ancestor, so category, summary and
   "Read more" are all the target. The whole card is one tap target on a
   phone, so the browser's tap flash would paint all of it: it is turned
   off here, and the press is answered by the card instead (see "taken"). */
.jn__link,
.jn__link:hover { color: inherit; }
.jn__link {
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.jn__link::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  border-radius: inherit;
}
.jn__link:focus-visible { outline: none; }
.jn:has(.jn__link:focus-visible) {
  outline: 2px solid var(--gold-light);
  outline-offset: 4px;
}

.jn__dek {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  overflow: hidden;
  font-size: 0.95rem;
  line-height: 1.65;
  color: var(--vein);
  overflow-wrap: anywhere;
  text-wrap: pretty;
}

/* "Read more": .link-line, drawn on a <p>. margin-top: auto pins it to the
   foot of the card, so it lines up across a row whatever the summaries say. */
.jn__go {
  position: relative;
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  gap: 0.5rem;
  margin-top: auto;
  padding: 0.35rem 0 0.25rem;
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--gold-light);
}
.jn__go::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: currentColor;
  opacity: 0.5;
  transform: scaleX(0.35);
  transform-origin: left;
  transition: transform 0.35s var(--ease-out), opacity 0.35s ease;
}
.jn__arrow { flex: none; transition: transform 0.35s var(--ease-out); }

/* ---- the article page's meta line (category, date, reading time) ---------
   A gold point between the parts. EVERY part carries one in a 1.1rem gutter
   on its left, and the row is pulled left by that gutter and clipped back
   to it - so the point on whichever part STARTS a line is cut off. A
   missing part, or a line that wraps on a phone, never leaves a separator
   hanging at the start of a line. */
.jn__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  row-gap: 0.2rem;
  margin-left: -1.1rem;
  clip-path: inset(-0.5rem -0.5rem -0.5rem 1.1rem);
  font-size: var(--text-xs);
  font-weight: 500;
  letter-spacing: 0.12em;
  line-height: 1.5;
  text-transform: uppercase;
  color: var(--vein);
  font-variant-numeric: tabular-nums;
}
.jn__meta > * { position: relative; padding-left: 1.1rem; overflow-wrap: anywhere; }
.jn__meta > *::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 0.42rem;
  width: 3px;
  height: 3px;
  margin-top: -2px;
  border-radius: 50%;
  background: var(--gold-shadow);
}
.jn__cat { color: var(--gold-light); font-weight: 600; }

/* ---- taken -------------------------------------------------------------
   Hover is for a fine pointer only (a tap on a phone would leave it stuck
   on); keyboard focus gets the same light. A press settles the card a hair,
   so a tap is answered the instant the finger lands, before the page
   leaves. */
@media (hover: hover) and (pointer: fine) {
  .jn:hover { border-color: var(--border-gold-strong); }
  .jn:hover .jn__title { color: var(--gold-light); }
  .jn:hover .jn__go::after { transform: scaleX(1); opacity: 1; }
  .jn:hover .jn__go .jn__arrow { transform: translateX(4px); }
  .jnl__all .link-line:hover svg { transform: translateX(4px); }
}
.jn:focus-within { border-color: var(--border-gold-strong); }
.jn:focus-within .jn__title { color: var(--gold-light); }
.jn:focus-within .jn__go::after { transform: scaleX(1); opacity: 1; }
.jn:active { transform: scale(0.99); }

/* the two standalone text links are short: their hit area is grown to a
   comfortable thumb without moving the underline or the text */
.jnl__all .link-line,
.rdr__back {
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.jnl__all .link-line::before,
.rdr__back::before {
  content: "";
  position: absolute;
  inset: -0.7rem -0.5rem;
}

/* "Show more", under the archive */
.jnl__more {
  display: flex;
  justify-content: center;
  margin-top: clamp(2.25rem, 1.75rem + 2vw, 3.5rem);
}
.jnl__more[hidden] { display: none; }
.jnl__more .btn.is-busy { opacity: 0.6; cursor: progress; }

/* a live update that brings in an article that was not on screen */
.jnl .is-new { animation: jnl-arrive 0.5s var(--ease-out) both; }
@keyframes jnl-arrive {
  from { opacity: 0; transform: translateY(10px); }
}

/* ==========================================================================
   States: loading, empty, error
   ========================================================================== */

/* The skeleton is the real card with its text swapped for bars, so the
   section is the right height at every width. One slow sheen crosses it -
   linear, because it is a constant process and not an arrival. */
.sk {
  background-color: rgba(214, 206, 196, 0.045);
  background-image: linear-gradient(100deg, transparent 20%, rgba(214, 206, 196, 0.06) 50%, transparent 80%);
  background-size: 220% 100%;
  background-repeat: no-repeat;
  animation: jnl-sheen 1.5s linear infinite;
}
.sk { display: block; height: 0.75rem; border-radius: var(--radius-sm); }
.sk--meta { width: min(9.5rem, 70%); height: 0.7rem; }
/* a card's category: the gold rule and the word, as one short bar */
.sk--label { width: min(8rem, 60%); height: 0.7rem; margin-block: 0.18rem 0.32rem; }
.sk--line { height: 0.9em; }
.sk--short { width: 62%; }
.sk--go { width: 6.5rem; height: 0.85rem; margin-top: auto; }
.jnl__skel .jn__title,
.jnl__skel .jn__dek { display: grid; gap: 0.4em; }
.jnl__skel .jn__title { padding-block: 0.1em; }
/* On a card, each bar takes a whole line of the text it stands for and
   paints only its middle, so a skeleton card is the height of a real one
   and nothing below it moves when the articles arrive. */
@supports (height: 1lh) {
  .jnl__skel .jn__title,
  .jnl__skel .jn__dek { gap: 0; padding-block: 0; }
  .jnl__skel .sk--line {
    height: 1lh;
    padding-block: calc((1lh - 0.9em) / 2);
    background-clip: content-box;
  }
}
/* "Read more": its padding and its line, the bar in between */
.jnl__skel .sk--go {
  height: calc(0.6rem + 0.9375rem * 1.7);
  padding-block: calc(0.35rem + (0.9375rem * 1.7 - 0.85rem) / 2) calc(0.25rem + (0.9375rem * 1.7 - 0.85rem) / 2);
  background-clip: content-box;
}
@keyframes jnl-sheen {
  from { background-position: 160% 0; }
  to   { background-position: -60% 0; }
}

/* Empty and error: a marble plate with the mark in its corner. It keeps the
   section's weight on the page, so "nothing yet" reads as a decision and
   not as a hole where something failed to arrive. */
.jnl__note {
  position: relative;
  overflow: hidden;
  display: grid;
  align-content: center;
  justify-items: start;
  gap: 0.6rem;
  min-height: clamp(13rem, 10rem + 8vw, 17rem);
  padding: clamp(1.75rem, 1.2rem + 2.2vw, 3.25rem);
  border: 1px solid var(--border-gold);
  border-radius: var(--jn-r); /* the same corner as the cards it stands in for */
  background:
    radial-gradient(110% 90% at 0% 0%, rgba(184, 145, 88, 0.08), transparent 60%),
    linear-gradient(150deg, var(--surface) 0%, var(--obsidian-raised) 60%, var(--obsidian) 100%);
}
.jnl__note::after {
  content: "";
  position: absolute;
  top: 50%;
  right: clamp(-3rem, -1rem - 2vw, -1.5rem);
  width: clamp(9rem, 6rem + 12vw, 17rem);
  aspect-ratio: 1;
  transform: translateY(-50%);
  background: url("../assets/mark-512.png") center / contain no-repeat;
  opacity: 0.07;
  pointer-events: none;
}
.jnl__note-h {
  position: relative;
  max-width: 24ch;
  font-size: clamp(1.2rem, 1.05rem + 0.6vw, 1.5rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.25;
  color: var(--white);
}
.jnl__note-p { position: relative; max-width: 34rem; color: var(--vein); text-wrap: pretty; }
.jnl__note-act { position: relative; margin-top: 0.75rem; }
.jnl__note .btn { min-height: 44px; touch-action: manipulation; }

/* ==========================================================================
   articles.html - the archive and the reader share one page. An inline
   script in its head sets html[data-view="article"] when the address names
   an article, before first paint, so the wrong view never flashes.
   ========================================================================== */

[data-view="article"] [data-view-index] { display: none; }
html:not([data-view="article"]) [data-view-article] { display: none; }

.jnl--archive { padding-top: 0; padding-bottom: clamp(3rem, 2rem + 3vw, 5rem); }

/* ---- the reader --------------------------------------------------------- */

.rdr {
  padding-top: calc(var(--jnl-nav-h) + clamp(2rem, 1.5rem + 2.5vw, 4rem));
  padding-bottom: clamp(3rem, 2rem + 3vw, 5rem);
}

/* one centred text column */
.rdr__article {
  display: grid;
  grid-template-columns:
    [full-start] minmax(0, 1fr)
    [text-start] minmax(0, 44rem)
    [text-end] minmax(0, 1fr) [full-end];
}
.rdr__article > * { grid-column: text; }

.rdr__head { display: grid; justify-items: start; gap: 1rem; }
.rdr__back { margin-bottom: clamp(0.5rem, 0.3rem + 1vw, 1.25rem); }
.rdr__back .jn__arrow { transition: transform 0.35s var(--ease-out); }
@media (hover: hover) and (pointer: fine) {
  .rdr__back:hover .jn__arrow { transform: translateX(-4px); }
}
.rdr__title {
  font-size: clamp(2rem, 1.5rem + 2.6vw, 3.6rem);
  letter-spacing: -0.035em;
  line-height: 1.06;
  overflow-wrap: anywhere;
  hyphens: auto;
}
.rdr__dek {
  max-width: 40rem;
  font-size: var(--text-lg);
  line-height: 1.6;
  color: var(--ink);
  overflow-wrap: anywhere;
  text-wrap: pretty;
}
.rdr__by { font-size: var(--text-sm); color: var(--vein); }

/* ---- the prose ---------------------------------------------------------- */

.rdr__body {
  max-width: 68ch;
  margin-top: clamp(2rem, 1.5rem + 2vw, 3rem);
  font-size: 1.125rem;
  line-height: 1.75;
  color: var(--ink);
  overflow-wrap: break-word;
}
.rdr__body > * + * { margin-top: 1.25em; }
.rdr__body h2 {
  margin-top: 2.2em;
  font-size: clamp(1.4rem, 1.2rem + 0.9vw, 1.85rem);
  letter-spacing: -0.025em;
  line-height: 1.2;
}
.rdr__body h3 {
  margin-top: 1.9em;
  font-size: clamp(1.15rem, 1.05rem + 0.5vw, 1.4rem);
  letter-spacing: -0.02em;
  line-height: 1.3;
}
.rdr__body h4 { margin-top: 1.6em; }
.rdr__body :is(h2, h3, h4) + * { margin-top: 0.7em; }
.rdr__body a {
  color: var(--gold-light);
  text-decoration: underline;
  text-decoration-color: var(--border-gold-strong);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.22em;
  transition: color 0.25s ease, text-decoration-color 0.25s ease;
}
.rdr__body a:hover { color: var(--white); text-decoration-color: currentColor; }
.rdr__body strong { font-weight: 600; color: var(--white); }
.rdr__body ul,
.rdr__body ol { display: grid; gap: 0.5em; padding-left: 1.3em; }
.rdr__body li::marker { color: var(--gold); }
.rdr__body blockquote {
  margin-block: 1.8em;
  padding-left: 1.25rem;
  border-left: 1px solid var(--gold);
  font-size: var(--text-xl);
  font-style: italic;
  line-height: 1.45;
  color: var(--gold-light);
}
.rdr__body hr {
  height: 1px;
  margin-block: 2.5em;
  border: 0;
  background: var(--border-neutral);
}
.rdr__body code {
  padding: 0.1em 0.35em;
  border: 1px solid var(--border-neutral);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
  font-size: 0.88em;
}
.rdr__body figure { margin-block: 2em; }
.rdr__body figure img {
  width: 100%;
  height: auto;
  border: 1px solid var(--border-gold);
  border-radius: var(--radius-md);
}

.rdr__end {
  margin-top: clamp(3rem, 2rem + 3vw, 4.5rem);
  padding-top: 1.5rem;
  border-top: 1px solid var(--border-neutral);
}

/* the reader's own skeleton and notes */
.rdr__skel {
  display: grid;
  gap: 0.9rem;
  max-width: 44rem;
  margin-inline: auto;
}
.rdr__skel .sk--title { height: clamp(2rem, 1.5rem + 2.6vw, 3.4rem); }
.rdr__skel .sk--p { height: 0.95rem; }
/* the space between the head and the prose, held open but not drawn */
.rdr__skel .sk--gap { height: clamp(1rem, 0.6rem + 1.5vw, 2rem); background: none; animation: none; }
.rdr .jnl__note { max-width: 44rem; margin-inline: auto; }

/* ---- reduced motion: no movement, nothing withheld ---------------------- */

@media (prefers-reduced-motion: reduce) {
  .sk,
  .jnl .is-new { animation: none; }
  .jn,
  .jn__title,
  .jn__go::after,
  .jn__arrow { transition: none; }
  .jn:active { transform: none; }
}
