/* updates.css — /updates index and permalinks.

   Tokens only: every colour, radius and type size here is a var() from tokens.css,
   so a grep for a hex value in this file returns nothing. Shared chrome (reset,
   nav, footer, buttons, focus rings) lives in base.css and is not repeated.

   Accent discipline: --accent is the gold FILL (email-capture button only) and
   --accent-ink is the gold TEXT (the date, and the one link treatment). It appears
   on neither the card borders nor the card titles, so the page does not turn gold.

   Motion: none. No scroll-reveal on this page — nothing here uses .reveal. */

/* ----------  Layout constants  ----------
   The article column is wider than the text column on purpose: a hero screenshot
   needs the width, running text does not. --u-text is ~70 characters of Inter at
   the body size, which is the comfortable measure for long-form reading. */
.u-head, .u-stream, .u-article, .u-prevnext, .u-signup {
  --u-col: 46rem;    /* article + hero width on a permalink */
  --u-text: 36rem;   /* ~70 characters of Inter: the reading measure */
  --u-list: 42rem;   /* the index list column */
}

/* ----------  Two-column layout  ----------
   A narrow archive sidebar, then a fixed reading column. The grid starts at the
   wrap's content edge so the sidebar lines up with the wordmark in the header,
   which means everything in the main column is left-aligned to one edge —
   including the page heading, and that is why it is not centred like the heroes
   on the marketing pages. Below the breakpoint the sidebar is hidden and the
   column re-centres: the index is already this list, and a permalink has both a
   back link and previous/next, so nothing is lost. */
.u-layout { display: grid; grid-template-columns: minmax(0, var(--u-list)); justify-content: center; }

/* ----------  Archive sidebar  ----------
   Hidden by default and switched on at the breakpoint below — these rules come
   first so the media query that reveals it wins on source order. */
.u-side { display: none; position: sticky; top: calc(64px + 1.5rem); align-self: start; max-height: calc(100vh - 96px); overflow-y: auto; }
.u-side-h { font-size: 0.75rem; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase; }
.u-side-h a { color: var(--ink-soft); text-decoration: none; }
.u-side-h a:hover { color: var(--ink); }
.u-side-year { margin-top: 1.25rem; font-size: 0.75rem; font-weight: 600; letter-spacing: 0.08em; color: var(--ink-faint); }
.u-side-list { list-style: none; margin-top: 0.4rem; border-left: 1px solid var(--line); }
.u-side-list a {
  display: block; padding: 0.35rem 0 0.35rem 0.8rem; margin-left: -1px;
  border-left: 2px solid transparent; text-decoration: none;
  transition: border-color .15s var(--ease), color .15s var(--ease);
}
.u-side-date { font-size: 0.8125rem; font-weight: 500; color: var(--ink-soft); white-space: nowrap; }
.u-side-list a:hover .u-side-date { color: var(--ink); }
.u-side-list a[aria-current="page"] { border-left-color: var(--ink); }
.u-side-list a[aria-current="page"] .u-side-date { color: var(--ink); font-weight: 600; }

@media (min-width: 1024px) {
  /* justify-content: start puts the sidebar's left edge on the wrap's content
     edge — the same line the Ginger wordmark sits on in the header. The reading
     column follows it rather than the page centre, which is why the whitespace
     sits on the right. */
  .u-layout {
    grid-template-columns: 7rem minmax(0, var(--u-list));
    gap: clamp(2rem, 4vw, 3rem);
    justify-content: start;
  }
  .u-side { display: block; }
  /* Pin the reading column to track 2 explicitly: on the empty state there is no
     sidebar element at all, and without this the content would drop into the
     narrow first track. */
  .u-main, .u-signup-inner { grid-column: 2; }
  /* Line the sidebar's first line up with the page eyebrow beside it, rather
     than with the top of the grid. */
  .u-stream .u-side { margin-top: clamp(2.5rem, 6vw, 4rem); }
}

/* ----------  Page head  ----------
   Centred within the reading column. Because the sidebar is narrow and the grid
   starts at the wrap edge, that column sits within ~16px of the page centre, so
   this reads as centred on the page while staying tied to the content below it. */
.u-head { padding-block: clamp(2.5rem, 6vw, 4rem) clamp(1.5rem, 4vw, 2.25rem); text-align: center; }
.u-head .eyebrow { margin-bottom: 0.9rem; }
.u-head h1 { font-size: clamp(2rem, 5vw, 3rem); font-weight: 500; letter-spacing: -0.03em; line-height: 1.1; }
.u-head .lead { margin-top: 1.1rem; max-width: var(--u-text); margin-inline: auto; }

/* ----------  Index: one column, one entry after another  ----------
   Every entry gets identical treatment - date, title, image, summary, link. The
   detail lives on the permalink, so the index stays scannable however long the
   list grows. Each entry is a white card on the page's off-white background, in
   the same shape as the cards elsewhere on the site. */
.u-stream { padding-block: 0 clamp(3rem, 7vw, 4.5rem); }

.u-entry {
  max-width: var(--u-list);
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: clamp(1.5rem, 4vw, 2rem);
}
.u-entry + .u-entry { margin-top: clamp(1rem, 2.5vw, 1.5rem); }
.u-entry-title {
  margin-top: 0.5rem;
  font-size: clamp(1.5rem, 3vw, 2rem); font-weight: 500;
  letter-spacing: -0.025em; line-height: 1.2;
}
.u-entry-title a { color: var(--ink); text-decoration: none; }
.u-entry-title a:hover { text-decoration: underline; text-underline-offset: 4px; text-decoration-thickness: 1px; }

.u-more { margin-top: 1.15rem; }
.u-more a { color: var(--accent-ink); font-weight: 600; font-size: 0.9375rem; text-decoration: none; }
.u-more a:hover { color: var(--accent-ink-deep); text-decoration: underline; text-underline-offset: 3px; }

/* Date — one of the three places the accent is allowed. */
.u-meta { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.6rem; }
.u-date {
  font-size: var(--type-label); font-weight: 600; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--accent-ink);
}
.u-byline { font-size: var(--type-label); color: var(--ink-soft); }

.u-summary { margin-top: 0.85rem; line-height: 1.55; color: var(--ink-soft); font-weight: 400; }
.u-entry .u-summary, .u-article .u-summary { font-size: clamp(1.0625rem, 1.6vw, 1.1875rem); }

/* ----------  Entry image  ----------
   Images do not have to be any particular shape. On the INDEX they are cropped
   to a 16:9 frame so the list keeps one rhythm however the screenshots were
   taken; on the PERMALINK the image keeps its own proportions, because there it
   is the thing you came to look at and cropping it would lose content. The
   generator writes intrinsic width/height either way, so neither shifts the
   layout while it loads. Entries without an image simply close up. */
.u-hero {
  margin-block: clamp(1.25rem, 3vw, 1.75rem);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  overflow: hidden; background: var(--surface);
}
.u-hero img { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; }
.u-hero-link { display: block; }
.u-article .u-hero { margin-top: 0; margin-bottom: clamp(1.5rem, 4vw, 2.25rem); }
.u-article .u-hero img { aspect-ratio: auto; object-fit: fill; }

/* ----------  Body copy (permalink only)  ---------- */
.u-body { max-width: var(--u-text); }
.u-body p { font-size: var(--type-body); line-height: 1.7; color: var(--ink); }
.u-body p + p { margin-top: 1.1em; }
.u-body a { color: var(--accent-ink); text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
.u-body a:hover { color: var(--accent-ink-deep); }
.u-body strong { font-weight: 600; }
.u-body code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.875em; background: var(--surface); border: 1px solid var(--line);
  border-radius: 4px; padding: 0.1em 0.35em;
}

/* base.css gives every <section> the full page rhythm; these are inside an article. */
.u-body .u-section { padding-block: 0; }
.u-section { margin-top: clamp(2rem, 5vw, 2.75rem); }
.u-lead p { font-size: clamp(1.0625rem, 1.5vw, 1.1875rem); line-height: 1.65; }

.u-h2 { font-size: 1.5rem; font-weight: 500; letter-spacing: -0.02em; line-height: 1.3; color: var(--ink); }
.u-h3, .u-h4 { font-size: 1.0625rem; font-weight: 600; letter-spacing: -0.01em; line-height: 1.4; color: var(--ink); margin-top: 1.75rem; }
.u-h2 + p, .u-h2 + ul, .u-h2 + ol, .u-h3 + p, .u-h4 + p { margin-top: 0.75rem; }

/* Anchor-linked sections: visible on hover, out of the a11y tree (aria-hidden). */
.u-anchor { margin-left: 0.35em; color: var(--ink-faint); text-decoration: none; opacity: 0; transition: opacity .15s var(--ease); }
.u-h2:hover .u-anchor { opacity: 1; }

.u-list { margin-top: 0.9rem; padding-left: 1.15rem; }
.u-list li { font-size: var(--type-body); line-height: 1.65; color: var(--ink); }
.u-list li + li { margin-top: 0.5rem; }
.u-list li::marker { color: var(--ink-faint); }

/* Figures in the body: a screenshot or a screen recording, framed like the hero.
   Above the sidebar breakpoint they widen to the full article column while the
   running text stays at its reading measure — screen recordings of a drawing
   view need the pixels, sentences do not. */
.u-figure { margin-block: 1.5rem; }
.u-figure img,
.u-figure video {
  display: block; width: 100%; height: auto;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface);
}
.u-figure figcaption { margin-top: 0.6rem; font-size: 0.875rem; color: var(--ink-soft); line-height: 1.5; }
@media (min-width: 1024px) { .u-figure { width: var(--u-list); } }

.u-quote { margin-top: 1.25rem; padding-left: 1rem; border-left: 2px solid var(--line); color: var(--ink-soft); }
.u-code {
  margin-top: 1.25rem; background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-sm); padding: 1rem 1.15rem; overflow-x: auto;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.8125rem; line-height: 1.6;
}
.u-hr { margin-block: 2rem; border: 0; border-top: 1px solid var(--line); }

/* ----------  "Also shipped" — plainer and denser than the sections above  ---------- */
.u-also { padding-top: 1.5rem; border-top: 1px solid var(--line); }
.u-also .u-h2 { font-size: var(--type-label); font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-soft); }
.u-also .u-list { margin-top: 0.75rem; }
.u-also .u-list li { font-size: 0.9375rem; line-height: 1.55; color: var(--ink-soft); }
.u-also .u-list li + li { margin-top: 0.3rem; }

/* ----------  "Known rough edges" — the .note shape from the style guide  ----------
   Candid, not an error state: an amber wash with readable dark-gold heading. This
   section is a credibility asset, so it has to look deliberate. */
.u-rough {
  background: var(--note-bg); border: 1px solid var(--note-line);
  border-radius: var(--radius-sm); padding: 1.15rem 1.35rem;
}
.u-rough .u-h2 { font-size: 1rem; font-weight: 600; letter-spacing: -0.005em; color: var(--accent-ink); }
.u-rough .u-list { margin-top: 0.6rem; }
.u-rough .u-list li { font-size: 0.9375rem; line-height: 1.6; }
.u-rough .u-list li::marker { color: var(--accent-ink); }
.u-rough p { font-size: 0.9375rem; line-height: 1.6; }

/* ----------  "What's next"  ---------- */
.u-next { background: var(--surface); border-radius: var(--radius-sm); padding: 1.15rem 1.35rem; }
.u-next .u-h2 { font-size: 1rem; font-weight: 600; letter-spacing: -0.005em; }
.u-next p { font-size: 0.9375rem; line-height: 1.65; color: var(--ink-soft); }


.u-empty { max-width: var(--u-text); color: var(--ink-soft); font-size: var(--type-lead); line-height: 1.5; }

/* ----------  Permalink page  ---------- */
.u-article { padding-block: clamp(2rem, 5vw, 3rem) clamp(3rem, 7vw, 4.5rem); }
.u-back { margin-bottom: clamp(1.5rem, 4vw, 2.25rem); }
.u-back a { font-size: 0.9375rem; font-weight: 500; color: var(--ink-soft); text-decoration: none; }
.u-back a:hover { color: var(--ink); }
.u-article-head { margin-bottom: clamp(1.75rem, 4vw, 2.5rem); }
.u-article-title { margin-top: 0.5rem; font-size: clamp(2rem, 5vw, 3rem); font-weight: 500; letter-spacing: -0.03em; line-height: 1.1; }
.u-article-head .u-summary { max-width: var(--u-text); }

/* ----------  Previous / next  ---------- */
.u-prevnext { display: block; border-top: 1px solid var(--line); margin-top: clamp(2.5rem, 6vw, 3.5rem); padding-top: clamp(2rem, 5vw, 2.75rem); }
.u-prevnext-inner { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; }
.u-prevnext-link {
  display: flex; flex-direction: column; gap: 0.3rem;
  border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 16px 18px;
  background: var(--bg); text-decoration: none; transition: border-color .2s var(--ease);
}
.u-prevnext-link:hover { border-color: var(--ink-faint); }
.u-prevnext-older { text-align: right; }
/* First and last update have only one neighbour: keep that box compact rather
   than stretching one link across the whole row. */
.u-prevnext-link:only-child { max-width: 24rem; }
.u-prevnext-older:only-child { margin-left: auto; }
.u-prevnext-label { font-size: var(--type-label); font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-soft); }
.u-prevnext-title { font-size: 0.9375rem; font-weight: 500; line-height: 1.4; color: var(--ink); }

/* ----------  Email capture — one field, one button, at the foot  ---------- */
.u-signup { background: var(--surface); border-top: 1px solid var(--line); padding-block: clamp(2.5rem, 6vw, 3.5rem); }
/* Sits in the layout grid's main column so it lines up with the article above it,
   while the --surface band behind it still runs the full width of the page. */
.u-signup-inner { display: grid; grid-template-columns: 1fr; gap: 1.25rem; }
.u-signup-copy h2 { font-size: 1.25rem; font-weight: 500; letter-spacing: -0.015em; }
.u-signup-copy p { margin-top: 0.4rem; font-size: 0.9375rem; color: var(--ink-soft); line-height: 1.5; }
.u-signup-form { display: grid; grid-template-columns: 1fr auto; gap: 0.6rem; align-items: start; }
.u-signup-form input {
  width: 100%; font: inherit; font-size: 0.9375rem; color: var(--ink);
  background: var(--bg); border: 1.5px solid var(--line); border-radius: var(--radius-sm);
  padding: 0.7rem 0.85rem; min-height: 48px;
  transition: border-color .2s var(--ease);
}
.u-signup-form input::placeholder { color: var(--ink-soft); }
.u-signup-form input:focus { outline: 3px solid var(--accent-ink); outline-offset: 1px; border-color: var(--accent-ink); }
.u-signup-form input[aria-invalid="true"] { border-color: var(--accent-ink); }
.u-signup-form .btn { white-space: nowrap; }
.u-signup-note { grid-column: 1 / -1; font-size: 0.8125rem; color: var(--ink-soft); line-height: 1.5; }
.u-signup-note.is-done { color: var(--accent-ink); font-weight: 500; }

@media (min-width: 720px) {
  .u-signup-inner { grid-template-columns: 1fr minmax(20rem, 24rem); align-items: start; gap: 2rem; }
}
@media (max-width: 520px) {
  .u-signup-form { grid-template-columns: 1fr; }
  .u-signup-form .btn { width: 100%; }
  .u-prevnext-older { text-align: left; }
}

/* Honeypot. Positioned off-screen rather than display:none, because some bots
   skip fields that are display:none — which would defeat the point. It is
   aria-hidden and tabindex="-1" in the markup, so nobody reaches it by keyboard
   or screen reader. */
.u-trap { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ----------  Utility  ---------- */
.u-sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
