/* Driven Life brand stylesheet.
   This file is the only stylesheet server-rendered pages load; there is no
   Tailwind server-side, so the :root block below is a copy of the design
   system's palette in web/src/styles/tokens.css.

   That copy silently went stale once already. The web tokens were moved to
   WCAG-AA values (production-readiness audit A4) and this file did not
   follow, so five of the fifteen colour tokens disagreed and this stylesheet
   still carried --color-caution: #D98E2B, the exact value measured at
   2.30:1 and replaced upstream, unused but waiting for the first template
   that reached for it. Neither existing gate could see it:
   check-contrast.mjs reads only tokens.css and check-tokens.sh greps only
   web/src.
   web/scripts/check-token-parity.mjs now compares this block against
   tokens.css in both directions, byte for byte, and runs in CI as part of
   `npm run check:tokens`. tokens.css is the source of truth; edit it there
   first, then mirror the value here and let the gate confirm it.

   Yellow (--color-reg) is a sticker, never a flood, and is never used as
   text color on a light ground (concrete, ground, or card) -- the one
   exception is the wordmark's N, which only ever sits on the plate-black
   header bar. */

:root {
  /* grounds */
  --color-concrete: #E3E4E0;
  --color-ground: #EDECE8;
  --color-card: #FBFAF7;
  --color-line: #DBDAD2;
  --color-steel: #C9C7BE;
  /* ink */
  --color-plate: #141412;
  --color-plate-soft: #232320;
  --color-bolt: #64635E;
  --color-faint: #908F89;
  /* accent: the sticker */
  --color-reg: #F2C230;
  /* semantic verdicts (never decorative) */
  --color-go: #2A7046;
  --color-go-tint: #E4EFE7;
  --color-caution: #8E5812;
  --color-caution-tint: #F5EDDC;
  --color-danger: #A84035;
  --color-danger-tint: #F5E4E1;
  /* type */
  --font-display: "Barlow Condensed", "Arial Narrow", Arial, sans-serif;
  --font-body: "Barlow", "Helvetica Neue", Arial, sans-serif;
  --font-mono: "IBM Plex Mono", Menlo, monospace;
  /* shape */
  --radius-card: 16px;
  --radius-control: 10px;
  --radius-sticker: 4px;
}

/* Breadcrumbs (task-11): the trail under the masthead on every page
   below the home, small and quiet, the same crumbs the BreadcrumbList
   structured data carries. */
.breadcrumbs {
  font-size: 13px;
  color: var(--color-bolt);
  padding-block: 10px;
  border-bottom: 1px solid var(--color-line);
}

.breadcrumbs ol {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0;
  padding: 0;
}

.breadcrumbs li + li::before {
  content: "/";
  margin-right: 8px;
  color: var(--color-steel);
}

.breadcrumbs a:hover,
.breadcrumbs a:focus-visible {
  color: var(--color-plate);
}

.breadcrumbs [aria-current="page"] {
  color: var(--color-plate);
}

/* The newsletter form's honeypot wrapper: off screen for people, present
   for bots (forms.py NewsletterSubscribeForm.website). */
.nf-hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* Visually hidden but still announced: the search form's own <label>
   (magazine-task-12) -- unlike .skip-link above, this content never
   becomes visible on focus, since a screen-reader-only label has nothing
   to reveal. Clipped, not `display: none`, so assistive tech still reads
   it. */
.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;
}

.skip-link {
  position: absolute;
  left: -999px;
  top: 8px;
  z-index: 100;
  background: var(--color-reg);
  color: var(--color-plate);
  padding: 8px 12px;
  border-radius: var(--radius-control);
  font-weight: 600;
}

.skip-link:focus {
  left: 8px;
}

/* Metric-tuned fallback faces (task-11, PORTFOLIO-PLAYBOOK section 6:
   "fonts: preload + metric-tuned fallbacks, no swap reflow"). Until the
   web fonts land, text renders in these local faces adjusted to occupy
   the same space, so the swap does not move a single line. The override
   values are approximations chosen against Arial and Arial Narrow's
   metrics to match Barlow's x-height and line box; measure with a font
   metrics tool and refine when the real font files are self-hosted. */
@font-face {
  font-family: "Barlow Fallback";
  src: local("Arial"), local("Helvetica Neue"), local("Helvetica");
  size-adjust: 98%;
  ascent-override: 93%;
  descent-override: 22%;
  line-gap-override: 0%;
}

@font-face {
  font-family: "Barlow Condensed Fallback";
  src: local("Arial Narrow"), local("Arial");
  size-adjust: 88%;
  ascent-override: 93%;
  descent-override: 22%;
  line-gap-override: 0%;
}

:root {
  --font-display: "Barlow Condensed", "Barlow Condensed Fallback", "Arial Narrow", Arial, sans-serif;
  --font-body: "Barlow", "Barlow Fallback", "Helvetica Neue", Arial, sans-serif;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--color-ground);
  color: var(--color-plate);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
}

h1,
h2,
h3,
h4 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.08;
  letter-spacing: 0.01em;
  margin: 0 0 0.5em;
}

h1 {
  font-size: clamp(2.25rem, 4vw + 1rem, 4rem);
}

h2 {
  font-size: clamp(1.5rem, 2vw + 1rem, 2.25rem);
}

p {
  margin: 0 0 1em;
}

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

img,
svg {
  max-width: 100%;
  height: auto;
  display: block;
}

.figures {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

/* Never take default browser focus rings away without replacing them; the
   reg outline reads on both the plate header and light grounds below. */
:focus-visible {
  outline: 2px solid var(--color-reg);
  outline-offset: 2px;
}

.container {
  /* 82.5rem is 1320px: the magazine front needs the room the old 72rem
     content site did not, and the owner read 72rem as narrow on a wide
     screen (2026-09-05). */
  max-width: 82.5rem;
  margin-inline: auto;
  padding-inline: 1rem;
}

@media (min-width: 640px) {
  .container {
    padding-inline: 1.5rem;
  }
}

@media (min-width: 1024px) {
  .container {
    padding-inline: 2rem;
  }
}

.eyebrow {
  display: block;
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-bolt);
  margin: 0 0 0.5em;
}

.card {
  background: var(--color-card);
  border: 1px solid var(--color-line);
  border-radius: var(--radius-card);
  padding: 1.25rem;
}

@media (min-width: 640px) {
  .card {
    padding: 1.5rem;
  }
}

.sticker {
  display: inline-block;
  background: var(--color-reg);
  color: var(--color-plate);
  border-radius: var(--radius-sticker);
  transform: rotate(-2deg);
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: 0.02em;
  padding: 0.15em 0.6em;
}

.btn-plate,
.btn-reg {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.9375rem;
  border-radius: var(--radius-control);
  padding: 0.6em 1.25em;
  border: 1px solid transparent;
  transition: opacity 120ms ease-out, transform 120ms ease-out;
}

.btn-plate {
  background: var(--color-plate);
  color: var(--color-reg);
}

.btn-plate:hover {
  opacity: 0.85;
}

.btn-reg {
  background: var(--color-reg);
  color: var(--color-plate);
}

.btn-reg:hover {
  opacity: 0.85;
}

/* The header's second, quieter call to action (Log in) next to the filled
   .btn-reg (Start the plan): same shape and sizing, transparent instead
   of filled, with the reg-yellow it is named for carried on the border
   and the text instead of the fill. */
.btn-reg-quiet {
  background: transparent;
  border-color: var(--color-reg);
  color: var(--color-reg);
}

.btn-reg-quiet:hover {
  opacity: 0.85;
}

/* ---- header ----
   .site-header/.site-nav (the pre-magazine header) are gone: base.html's
   header is now .masthead/.nav (task-3, below). .wordmark stays here --
   both the masthead and the footer use it. */

.wordmark {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.125rem;
  letter-spacing: 0.18em;
  color: var(--color-concrete);
}

/* The one place yellow text is allowed: the N sits on the plate-black
   header/footer ground, never on a light ground. */
.wordmark .n {
  color: var(--color-reg);
}

/* ---- hero ---- */

.hero {
  background: var(--color-plate);
  color: var(--color-concrete);
  padding-block: 2.5rem;
}

@media (min-width: 640px) {
  .hero {
    padding-block: 3.5rem;
  }
}

.hero h1 {
  color: var(--color-concrete);
  max-width: 40rem;
}

.hero .eyebrow {
  color: var(--color-faint);
}

.hero-body {
  max-width: 38rem;
  color: var(--color-steel);
}

/* ---- content sections ---- */

.section {
  padding-block: 2rem;
}

@media (min-width: 640px) {
  .section {
    padding-block: 3rem;
  }
}

.section .empty-state {
  color: var(--color-bolt);
  max-width: 34rem;
}

/* ---- card grid (story/article listings) ---- */

.card-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
  margin-top: 1.5rem;
}

@media (min-width: 640px) {
  .card-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 1.5rem;
  }
}

@media (min-width: 1024px) {
  .card-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

.story-card {
  display: block;
  transition: transform 120ms ease-out, border-color 120ms ease-out;
}

.story-card:hover,
.story-card:focus-visible {
  border-color: var(--color-steel);
  transform: translateY(-2px);
}

.story-card h2,
.story-card h3 {
  margin-bottom: 0.35em;
}

.story-card__meta {
  font-size: 0.8125rem;
  color: var(--color-bolt);
  margin-bottom: 0.75em;
}

.story-card__quote {
  color: var(--color-plate-soft);
  margin: 0;
}

/* ---- pagination ---- */

.pagination {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1.5rem;
  margin-top: 2rem;
  font-weight: 600;
  font-size: 0.875rem;
}

.pagination__link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--color-plate);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

.pagination__status {
  color: var(--color-bolt);
}

/* ---- story page ---- */

.story-hero__meta {
  color: var(--color-steel);
  font-size: 0.9375rem;
  margin-bottom: 1.5rem;
}

.hero-quote {
  margin: 0;
  padding: 0;
  border: none;
  max-width: 42rem;
  font-family: var(--font-body);
  font-style: italic;
  font-size: clamp(1.375rem, 1.5vw + 1rem, 1.75rem);
  color: var(--color-concrete);
  line-height: 1.4;
}

.sponsor-disclosure {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
}

.sponsor-disclosure p {
  margin: 0;
  color: var(--color-bolt);
}

.story-question {
  max-width: 65ch;
  margin: 0 auto 3rem;
}

.story-question:last-child {
  margin-bottom: 0;
}

.cta-block .cta-plate {
  background: var(--color-plate);
  color: var(--color-concrete);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
}

.cta-block .cta-plate p {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.375rem;
}

/* ---- likes card (story page) ----
   task-15: the companion post's like count and public comments, sent
   into view straight off the app's own data -- no new visual language,
   just .card/.eyebrow/.btn-reg/.btn-reg-quiet already carrying every
   other card and call to action on this page. */
.conversation {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1.5rem;
}

@media (min-width: 48rem) {
  .conversation {
    grid-template-columns: minmax(0, 1fr) 260px;
    gap: 2rem;
  }
}

.conversation-main {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  min-width: 0;
}

.conversation-title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.25rem;
  line-height: 1.2;
  color: var(--color-plate);
}

.conversation-dot {
  color: var(--color-steel);
  margin: 0 0.25rem;
}

.conversation-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
}

.conversation-item {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
}

.conversation-avatar {
  flex-shrink: 0;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 9999px;
  background: var(--color-plate);
  color: var(--color-reg);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.9375rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

.conversation-avatar-you {
  background: var(--color-line);
  color: var(--color-bolt);
}

.conversation-body {
  flex: 1;
  min-width: 0;
  background: var(--color-ground);
  border-radius: 12px;
  padding: 0.6rem 0.85rem;
}

.conversation-meta {
  margin: 0 0 0.15rem;
  font-size: 0.8125rem;
  color: var(--color-bolt);
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  align-items: baseline;
}

.conversation-author {
  font-weight: 600;
  color: var(--color-plate);
}

.conversation-handle {
  color: var(--color-bolt);
}

.conversation-text {
  margin: 0;
  color: var(--color-plate);
  line-height: 1.5;
}

.conversation-more {
  align-self: flex-start;
  font-size: 0.875rem;
  font-weight: 600;
}

.conversation-empty {
  margin: 0;
  color: var(--color-bolt);
}

.conversation-reply {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  text-decoration: none;
  color: inherit;
}

.conversation-reply-field {
  flex: 1;
  min-width: 0;
  height: 2.5rem;
  border-radius: 9999px;
  border: 1px solid var(--color-line);
  background: var(--color-card);
  padding: 0 1rem;
  display: flex;
  align-items: center;
  color: var(--color-bolt);
}

.conversation-reply:hover .conversation-reply-field {
  border-color: var(--color-plate);
  color: var(--color-plate);
}

.conversation-reply-hint {
  font-size: 0.8125rem;
  color: var(--color-bolt);
  white-space: nowrap;
}

.conversation-side {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  align-items: stretch;
  border-top: 1px solid var(--color-line);
  padding-top: 1.25rem;
}

@media (min-width: 48rem) {
  .conversation-side {
    border-top: 0;
    border-left: 1px solid var(--color-line);
    padding: 0 0 0 2rem;
  }
}

.conversation-likes {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  color: var(--color-plate);
  margin-bottom: 0.25rem;
}

.conversation-likes svg {
  align-self: center;
  color: var(--color-danger);
}

.conversation-likes-count {
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 1.75rem;
  line-height: 1;
}

.conversation-likes-label {
  color: var(--color-bolt);
}

.conversation-side .btn-reg,
.conversation-side .btn-reg-quiet {
  justify-content: center;
  gap: 0.5em;
}

.conversation-note {
  margin: 0.25rem 0 0;
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--color-bolt);
}

/* ---- footer ----
   .site-footer/.footer-meta/.footer-wordmark (the pre-magazine footer)
   are gone: base.html's footer is now .footer (task-3, below).
   .newsletter-placeholder stays here -- the magazine footer still wraps
   content/_newsletter_form.html in one. */

.newsletter-placeholder {
  margin-bottom: 1.5rem;
}

/* ---- newsletter form (footer, task-6) ----
   "Reg on plate": the form itself sits on a light card ground (a plate)
   against the footer's dark plate-soft, and the submit button is a
   .btn-reg sticker on it. The card also keeps error text (--color-danger)
   on a light ground, which is where this project's tokens are tuned for
   AA contrast -- neither --color-danger nor its dark-ground counterpart is
   safe directly on --color-plate-soft. */
.newsletter-form {
  max-width: 32rem;
}

.newsletter-form .eyebrow {
  margin-bottom: 0.75rem;
}

.newsletter-form__row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.75rem 1rem;
}

.newsletter-form__field {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  flex: 1 1 14rem;
}

.newsletter-form__label {
  font-weight: 600;
  font-size: 0.8125rem;
  letter-spacing: 0.02em;
  color: var(--color-plate-soft);
}

.newsletter-form__input {
  min-height: 44px;
  padding: 0.6em 0.85em;
  border-radius: var(--radius-control);
  /* --color-steel only reaches 1.62:1 against the card's --color-card
     background (and 1.43:1 against this input's own --color-ground fill)
     -- short of WCAG 1.4.11's 3:1 floor for a UI component boundary.
     --color-bolt clears both (5.77:1 on the card, 5.09:1 on the input
     fill, remeasured after the token was brought back into agreement with
     web/src/styles/tokens.css) and is already this page's token for
     exactly this "visible but quiet" boundary role (.eyebrow uses it
     above). */
  border: 1px solid var(--color-bolt);
  background: var(--color-ground);
  color: var(--color-plate);
  font-family: var(--font-body);
  font-size: 0.9375rem;
}

.newsletter-form__input[aria-invalid="true"] {
  border-color: var(--color-danger);
}

.newsletter-form__error {
  margin: 0;
  color: var(--color-danger);
  font-size: 0.8125rem;
  font-weight: 600;
}

.newsletter-form__submit {
  flex: 0 0 auto;
}

/* ---- article cards (articles index, home, related-articles footer) ---- */

.article-card,
.related-article-card {
  display: block;
  transition: transform 120ms ease-out, border-color 120ms ease-out;
}

.article-card:hover,
.article-card:focus-visible,
.related-article-card:hover,
.related-article-card:focus-visible {
  border-color: var(--color-steel);
  transform: translateY(-2px);
}

.article-card h2,
.article-card h3,
.related-article-card h3 {
  margin-top: 0.35em;
  margin-bottom: 0.35em;
}

.article-card__intro {
  color: var(--color-plate-soft);
  margin: 0;
}

/* ---- category filter chips (articles index) ---- */

.category-filter {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
}

.chip {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0.4em 1em;
  border: 1px solid var(--color-line);
  border-radius: var(--radius-control);
  background: var(--color-card);
  color: var(--color-bolt);
  font-weight: 600;
  font-size: 0.875rem;
}

.chip:hover,
.chip:focus-visible {
  border-color: var(--color-steel);
  color: var(--color-plate);
}

.chip--active {
  background: var(--color-reg);
  border-color: var(--color-reg);
  color: var(--color-plate);
}

/* The mockup's own name for the same "selected" state (design/magazine/
   _shared.css); `.chip--active` above predates the magazine mockups and
   still styles the pre-existing Articles/Stories index chips. News (task-4)
   and any later section that copies the mockup's markup verbatim use this
   one instead of renaming the mockup's class to match the older one. */
.chip-on {
  background: var(--color-reg);
  border-color: var(--color-reg);
  color: var(--color-plate);
}

/* ---- the Events front's Where row (task-14 section B): the state
   chips reuse .category-filter/.chip/.chip-on as-is (the mockup's own
   "selected" language, same as the kind chips below them); this only
   adds the metro <select> form that sits under them. ---- */

.metro-filter {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 24px;
  font-size: 0.875rem;
  color: var(--color-bolt);
}

.metro-filter select.input {
  min-width: 12rem;
}

/* A one-line note under a section head (task-14 section C's "N upcoming
   in M states", home_page.html) -- quieter than .dek, closer in weight
   to .meta, but its own class since neither sits directly under a
   section-head anywhere else. */
.section-note {
  margin: 4px 0 0;
  font-size: 13px;
  color: var(--color-bolt);
}

/* ---- article page ---- */

.article-hero .article-byline {
  color: var(--color-steel);
  font-size: 0.9375rem;
  margin: 0;
}

.article-body-section {
  padding-block: 2.5rem;
}

.article-measure {
  max-width: 42rem;
  margin-inline: auto;
  line-height: 1.75;
}

.article-dek {
  font-size: 1.125rem;
  color: var(--color-bolt);
  margin-bottom: 2rem;
}

.article-block-heading {
  margin-top: 2rem;
}

.article-block-paragraph {
  margin-bottom: 1.5rem;
}

.article-block-paragraph p:last-child {
  margin-bottom: 0;
}

.article-pull-quote {
  margin: 2rem 0;
  padding: 0;
  border: none;
  border-left: 3px solid var(--color-reg);
  padding-left: 1.25rem;
  font-family: var(--font-body);
  font-style: italic;
  font-size: clamp(1.25rem, 1.2vw + 1rem, 1.625rem);
  color: var(--color-plate-soft);
  line-height: 1.5;
}

.article-callout {
  margin: 2rem 0;
}

.article-callout .sticker {
  margin-bottom: 0.75rem;
}

.article-callout__title {
  margin-bottom: 0.5em;
}

.article-callout__text :last-child {
  margin-bottom: 0;
}

/* ---- related articles footer ---- */

.related-articles .eyebrow {
  color: var(--color-bolt);
}

/* ============================================================
   The magazine (task-3): masthead, footer, front-page layout, the
   ad family, and article furniture. Lifted from the approved mockup
   (design/magazine/_shared.css, design/magazine/parts/*.html) onto
   this file's own tokens rather than the mockup's raw hex.

   The mockup's `.phone` parent class becomes `@media (max-width:
   639px)` at the foot of this section, matching this file's own
   640px breakpoint -- the other direction from `.container`/`.card`
   above (those are authored mobile-first with `min-width: 640px`
   desktop overrides; the classes below are authored desktop-first,
   like the mockup itself, so their phone overrides go the other
   way). Classes the rest of this file already carries and section
   templates keep using as-is -- `.btn-reg`, `.btn-reg-quiet`,
   `.card`, `.eyebrow`, `.sticker`, `.chip` -- are not repeated here.
   ============================================================ */

/* ---- masthead ---- */

.masthead {
  background: var(--color-plate);
  color: var(--color-concrete);
}

.masthead-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding-block: 16px;
}

.nav {
  display: flex;
  align-items: center;
  gap: 24px;
  font-weight: 600;
  font-size: 14px;
}

.nav a {
  color: var(--color-steel);
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}

.nav a.on {
  color: var(--color-concrete);
  box-shadow: inset 0 -2px 0 var(--color-reg);
}

/* The mockup (build.mjs) wraps the two front-door buttons in an inline-
   styled div; that div's `style` attribute is a CSS class here instead,
   since this content site's CSP `style-src` has no `'unsafe-inline'` (an
   inline `style=""` is silently dropped by the browser, not merely a
   lint concern) -- see config/csp.py's PUBLIC policy. */
.masthead-actions {
  display: flex;
  gap: 12px;
  align-items: center;
}

/* The masthead's search entry (owner's call, 2026-09-06): a magnifier
   icon that links to /search/, where the full form lives, instead of an
   inline field crowding the sections row. 44px square for the tap target,
   steel at rest, concrete on hover and focus, like the section links. */
.search-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-control);
  color: var(--color-steel);
}

.search-link:hover,
.search-link:focus-visible,
.search-link[aria-current="page"] {
  color: var(--color-concrete);
}

/* Site search (magazine-task-12): content/_search_form.html, included at
   the top of search.html and nowhere else -- the masthead's own entry is
   the .search-link icon above. The compact variant this file used to
   carry (a dark-ground field for the masthead plus a CSS-only checkbox
   toggle for phones) went with the branch that rendered it,
   magazine-final I5. */
.search-form {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 20px 0;
}

.search-field {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1 1 auto;
}

.search-form .search-field input[type="search"] {
  height: 44px;
  flex: 1 1 auto;
  max-width: 28rem;
  border: 1px solid var(--color-line);
  background: var(--color-card);
  border-radius: var(--radius-control);
  padding: 0 12px;
  font-size: 1rem;
  color: var(--color-plate);
}

.search-form .search-submit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.9375rem;
  border-radius: var(--radius-control);
  padding: 0.6em 1.25em;
  background: transparent;
  color: var(--color-plate);
  border: 1px solid var(--color-line);
  cursor: pointer;
}

.masthead-line {
  border-top: 1px solid var(--color-plate-soft);
}

.dateline {
  display: flex;
  justify-content: space-between;
  font-size: 13px;
  color: var(--color-faint);
  padding-block: 8px;
}

/* ---- ad slots: reserved height, labeled, provider-gated by the
   `ad_slot` template tag (content/templatetags/ads.py, task-1) so
   nothing empty ever ships (ADSENSE-RUNBOOK). ---- */

.ad-band {
  padding-block: 16px;
  display: flex;
  justify-content: center;
}

.ad {
  background: repeating-linear-gradient(135deg, var(--color-concrete) 0 10px, var(--color-line) 10px 20px);
  border: 1px dashed var(--color-steel);
  border-radius: 4px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  color: var(--color-bolt);
  box-sizing: border-box;
  margin-inline: auto;
  max-width: 100%;
  overflow: hidden;
}

.ad-label {
  font-family: var(--font-body);
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* AdSense's own <ins> is a flex item of the .ad container above, so with
   no width of its own it shrinks to nothing: measured 0px wide in the
   browser, which is the width Google's script reads before it decides
   there is no slot size available and leaves the unit blank. It fills
   the container instead, which is also what makes the lazy push in
   site.js fire at all (magazine-final C1). */
.ad .adsbygoogle {
  width: 100%;
  flex: 1 1 auto;
}

.ad-leaderboard_atf { width: 970px; }
.ad-leaderboard_btf { width: 728px; }
.ad-sidebar_atf,
.ad-sidebar_btf,
.ad-content,
.ad-feed { width: 300px; }

/* Reserved height per unit, keyed off the `data-unit` attribute
   `_ad_slot.html` always emits (magazine-task-4: moved out of that
   template's own inline `style`, which the public policy's style-src with
   no 'unsafe-inline' silently dropped -- see that template's comment).
   Desktop sizes match `UNITS` in content/templatetags/ads.py; the phone
   overrides sit in the max-width: 639px block below and only differ for
   leaderboard_atf, whose phone creative is shorter than its desktop one. */
.ad[data-unit="leaderboard_atf"] { min-height: 250px; }
.ad[data-unit="leaderboard_btf"] { min-height: 90px; }
.ad[data-unit="sidebar_atf"] { min-height: 250px; }
.ad[data-unit="sidebar_btf"] { min-height: 600px; }
.ad[data-unit="content"] { min-height: 250px; }
.ad[data-unit="feed"] { min-height: 250px; }
.ad[data-unit="adhesion"] { min-height: 50px; }

.ad-sticky {
  position: sticky;
  top: 24px;
}

/* Adhesion ships on phones only (placement per the design spec); hidden
   here, pinned to the viewport bottom under the phone media query below.
   site.js adds the `.ad-dismiss` button and wires its click. */
.ad-adhesion {
  display: none;
  width: 320px;
}

.ad-dismiss {
  border: 0;
  background: transparent;
  color: var(--color-bolt);
  font-size: 20px;
  line-height: 1;
  min-width: 44px;
  min-height: 44px;
  cursor: pointer;
}

/* ---- front page: lead story, card grids, news rows, rail ---- */

/* A section front's own eyebrow/h1/dek header (the News mockup's plain
   light-ground treatment, distinct from the older Articles/Stories
   `.hero` dark banner above). */
.section-intro { padding-top: 32px; }
.section-intro .dek { max-width: 640px; }

/* Two columns, and always three children in this DOM order: the prose
   `<article id="article-body">`, the `<aside class="rail">` that has to
   stay its immediate next sibling for Mediavine's `article + aside`
   sidebar selector (MEDIAVINE-RUNBOOK 2b), and `.main-sections` --
   everything else the main column carries (card grids and row lists,
   each with its own `data-ad-feed` hook, which is exactly why they can
   no longer live inside the content hook: MEDIAVINE-RUNBOOK item 2,
   magazine-final I2).

   The two explicit rows are what let the rail span the whole main column
   with `grid-row: 1 / -1`: `-1` counts lines of the EXPLICIT grid only,
   so without `grid-template-rows` here it would resolve back to row 1
   and the rail would size a row of its own. `row-gap: 0` keeps the seam
   between the two rows invisible, so the section heads' own margins set
   that spacing exactly as they did when this was one flow. */
.front {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  grid-template-rows: auto auto;
  column-gap: 32px;
  row-gap: 0;
  align-items: start;
  padding-block: 32px;
}

.front > *,
.art-layout > * { grid-column: 1; }

/* The rail spans, and stretches to, the full height of the main column.
   That stretch is what gives `.ad-sticky` -- the last element in the
   rail, and the top desktop earner -- real travel to ride: a rail only
   as tall as its own contents would cage the unit just as surely as the
   `position: sticky` this rule replaced (MEDIAVINE-RUNBOOK item 3,
   magazine-final I1). */
.front > .rail,
.art-layout > .rail {
  grid-column: 2;
  grid-row: 1 / -1;
  align-self: stretch;
}

/* A front's own intro is the prose inside the content hook now, so the
   grid's top padding already supplies the space this once added. */
.front .section-intro { padding-top: 0; }

.lead {
  display: grid;
  grid-template-columns: 1.15fr 1fr;
  gap: 24px;
  align-items: stretch;
}

.photo {
  background: linear-gradient(160deg, var(--color-plate-soft) 0%, var(--color-bolt) 55%, var(--color-steel) 100%);
  border-radius: var(--radius-card);
  position: relative;
  overflow: hidden;
  min-height: 200px;
}

.photo span {
  position: absolute;
  left: 12px;
  bottom: 10px;
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(251, 250, 247, 0.85);
  font-family: var(--font-display);
  font-weight: 600;
}

.photo-wide { min-height: 380px; }
.photo-card { min-height: 160px; border-radius: var(--radius-control); }

/* task-13 section A: the hero's own <figure>/<figcaption> wrapper
   (article_page.html, news_page.html, story_page.html, event_page.html).
   .photo itself is untouched -- this only resets the browser default
   margin a bare <figure> would otherwise add around it, and styles the
   caption line below. */
.photo-figure { margin: 0; }
.photo-caption { margin-top: 8px; font-size: 13px; color: var(--color-bolt); }

/* A real <img> (task-4's NewsPage.hero_image, {% image %}) inside `.photo`
   fills the same box the mockup's gradient placeholder occupies, rather
   than sitting inline at its natural size above it. */
.photo img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: inherit;
}

.lead-copy h2 {
  font-size: 44px;
  line-height: 1.02;
  margin: 8px 0 12px;
}

.dek {
  font-size: 18px;
  line-height: 1.5;
  color: var(--color-bolt);
  margin: 0 0 16px;
}

.byline { font-size: 13px; color: var(--color-bolt); }
.byline b { color: var(--color-plate); font-weight: 600; }

.grid3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 24px; margin-top: 24px; }
.grid2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px; margin-top: 24px; }

.grid3 .card h3,
.grid2 .card h3 { font-size: 22px; line-height: 1.1; margin: 10px 0 6px; }
.grid3 .card p,
.grid2 .card p { color: var(--color-plate-soft); margin: 0; }
.grid3 .card .meta,
.grid2 .card .meta { font-size: 13px; color: var(--color-bolt); margin-top: 10px; }

.card-sponsored { border-color: var(--color-reg); }

/* ---- home front (magazine-task-6) ----
   Spacing for a card whose first child is the photo (or its placeholder):
   the mockup gives the eyebrow/sponsor row right after it a top margin so
   it does not sit flush against the image. `.sponsor-row` is this file's
   own class for the mockup's inline "sticker + eyebrow, side by side"
   pattern (design/magazine/parts/Main.html has it as an inline style;
   this project's public policy carries no style-src 'unsafe-inline'
   under ADS_PROVIDER=none, so nothing here uses the `style` attribute --
   see magazine-task-4's report for the same reasoning applied to ad
   units). */
.photo-card + .eyebrow,
.photo-card + .sponsor-row { margin-top: 12px; }

.sponsor-row { display: flex; align-items: center; gap: 10px; }
.sponsor-row .eyebrow { margin: 0; }

/* An Events grid3 card: a date sticker beside the details, rather than
   the newsrow-shaped `.event` the Events section front uses. */
.card-event { display: flex; gap: 16px; align-items: flex-start; }
.card-event h3 { margin-top: 0; }
.card-event .meta { margin-top: 0; }
.card-event .btn { margin-top: 12px; min-height: 36px; }

/* The phone-only feed ad cell inside the "From the road" grid (spec 5:
   home gets "one feed unit on phones"). Always rendered so the markup is
   identical at both sizes; hidden here rather than left out of the DOM
   at 640px and up, where the leaderboard/sidebar slots already cover the
   placement this unit exists for on a phone. */
@media (min-width: 640px) {
  .ad-feed-phone { display: none; }
}

.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  margin-top: 40px;
  border-top: 1px solid var(--color-line);
  padding-top: 24px;
}

.section-head h2 { font-size: 36px; margin: 0; }
.section-head a { font-weight: 600; font-size: 14px; color: var(--color-bolt); }

.newsrow {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr);
  gap: 20px;
  padding: 20px 0;
  border-top: 1px solid var(--color-line);
}

.newsrow:first-of-type { border-top: 0; }
/* ...except where the list opens under a section head, which is how the
   home front separates the heading from its first row. */
.section-head + .newslist .newsrow:first-of-type { border-top: 1px solid var(--color-line); }
.newsrow time { font-family: var(--font-mono); font-size: 13px; color: var(--color-bolt); padding-top: 6px; }
.newsrow h3 { font-size: 24px; margin: 0 0 6px; }
.newsrow p { margin: 0; color: var(--color-plate-soft); }

/* A search result's matched term (magazine-task-12, the mark_terms
   filter): the same reg-yellow the sticker/chip-on language already
   uses, as a highlighter background rather than flood text. */
mark {
  background: var(--color-reg);
  color: var(--color-plate);
  border-radius: 2px;
  padding: 0 0.15em;
}

/* An <aside> that is the immediate next sibling of a literal <article>,
   so the sidebar ad selector matches (MEDIAVINE-RUNBOOK 2b).

   Deliberately NOT sticky (magazine-final I1). A sticky element inside a
   pinned sticky ancestor has no travel of its own: once the rail pinned
   at `top: 24px` it never moved again, so `.ad-sticky` was inert and
   `sidebar_btf`, the last element in the rail, sat permanently above the
   fold on any rail taller than the viewport. MEDIAVINE-RUNBOOK item 3 is
   explicit that this unit is the one that earns extra impressions
   without extra pageviews and that CSS is what usually kills it, and
   quotes Mediavine's own guidance that disabling the sidebar's sticky
   behaviour is what lets their script place the unit. So the rail
   scrolls and only the ad inside it sticks. */
.rail {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.rail .card { padding: 16px; }
.rail h4 { font-size: 18px; margin: 6px 0 8px; }
.rail ul { margin: 0; padding: 0; }
.rail li { font-size: 15px; line-height: 1.4; padding: 8px 0; border-top: 1px solid var(--color-line); list-style: none; }
.rail li:first-child { border-top: 0; padding-top: 0; }

.input {
  height: 44px;
  border: 1px solid var(--color-line);
  background: var(--color-card);
  border-radius: var(--radius-control);
  padding: 0 12px;
  font-size: 14px;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  color: var(--color-bolt);
}

/* A transparent, plate-outlined secondary button (the mockup's
   `.btn.btn-outline`, e.g. an event's "RSVP in the app"). Self-
   contained, unlike `.btn-reg-quiet` above, so a template can use it
   alone rather than pairing it with another `.btn-` class. */
.btn-outline {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.9375rem;
  border-radius: var(--radius-control);
  padding: 0.6em 1.25em;
  background: transparent;
  color: var(--color-plate);
  border: 1px solid var(--color-line);
}

/* ---- the Events front's map (task-14 section C, _us_map.html): hidden
   on phones, where the list below it is the map (spec: "at 640px and
   up"). State fill is concrete with a steel outline; the state named by
   an active ?state= filter gets plate-soft instead; dots are reg, the
   same sticker yellow the date stickers use. */

.us-map-wrap {
  display: none;
}

@media (min-width: 640px) {
  .us-map-wrap {
    display: block;
    margin-bottom: 24px;
  }
}

.us-map {
  display: block;
  width: 100%;
  height: auto;
}

.us-map-state {
  fill: var(--color-concrete);
  stroke: var(--color-steel);
  stroke-width: 1;
}

.us-map-state-active {
  fill: var(--color-plate-soft);
}

.us-map-inset-frame {
  fill: none;
  stroke: var(--color-steel);
  stroke-dasharray: 3 3;
}

.map-dot {
  fill: var(--color-reg);
  stroke: var(--color-plate);
  stroke-width: 1;
}

.map-dot-link:hover .map-dot,
.map-dot-link:focus .map-dot {
  fill: var(--color-plate);
}

/* The map's own hover/focus card (site.js' initMapHoverCard, task-14
   section C): a fixed caption under the map rather than a tooltip that
   follows the pointer, so the same element works for a mouse hover and
   for keyboard focus, which has no pointer position to follow. Hidden by
   default via the `hidden` attribute site.js sets/clears directly. */
.map-hover-card {
  margin-top: 8px;
  padding: 8px 12px;
  border: 1px solid var(--color-line);
  border-radius: var(--radius-control);
  background: var(--color-card);
  font-size: 13px;
  color: var(--color-plate-soft);
}

/* ---- events: a date sticker per event, the same sticker language
   as the member app's plate ---- */

.sticker-date {
  flex-direction: column;
  width: 56px;
  height: 56px;
  padding: 0;
  line-height: 1;
  font-size: 12px;
  transform: rotate(2deg);
}

.sticker-date b { font-size: 24px; display: block; margin-top: 2px; }

.event {
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr) auto;
  gap: 20px;
  align-items: start;
  padding: 20px 0;
  border-top: 1px solid var(--color-line);
}

.event h3 { font-size: 24px; margin: 0 0 4px; }
.event .where { font-size: 14px; color: var(--color-bolt); }
.event p { margin: 8px 0 0; color: var(--color-plate-soft); }

/* An EventPage's own date sticker beside its "when" line (task-5), at the
   top of the article body -- the same sticker language as .event above,
   just laid out for one event instead of a row of them. */
.event-when {
  display: flex;
  align-items: center;
  gap: 16px;
  margin: 0 0 24px;
}

.event-when .where { font-size: 15px; color: var(--color-bolt); }

/* ---- article ---- */

.art-hero {
  background: var(--color-plate);
  color: var(--color-concrete);
  padding-block: 48px;
}

.art-hero h1 { font-size: 64px; color: var(--color-concrete); max-width: 800px; margin: 8px 0 12px; }
.art-hero .dek { color: var(--color-steel); max-width: 640px; }
.art-hero .byline { color: var(--color-steel); }
.art-hero .byline b { color: var(--color-concrete); }
.art-hero .eyebrow { color: var(--color-faint); }

/* The article/author two-column layout: the same three-child shape
   `.front` documents above, and the same reason for the explicit rows
   (an author page carries a `.main-sections` block; an article page has
   only the article and the rail, whose empty second row costs nothing
   at `row-gap: 0`). */
.art-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  grid-template-rows: auto auto;
  column-gap: 48px;
  row-gap: 0;
  align-items: start;
  padding-block: 40px;
}

.measure { max-width: 760px; line-height: 1.75; }
.measure p { margin: 0 0 24px; font-size: 17px; }
.measure h2 { font-size: 32px; margin: 40px 0 12px; }
.measure .photo { margin-bottom: 24px; }

.pull {
  border-left: 4px solid var(--color-reg);
  padding: 4px 0 4px 20px;
  margin: 32px 0;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 28px;
  line-height: 1.15;
}

.callout {
  background: var(--color-card);
  border: 1px solid var(--color-line);
  border-radius: var(--radius-card);
  padding: 20px;
  margin: 32px 0;
}

.callout .sticker { margin-bottom: 8px; }

.disclosure {
  display: flex;
  align-items: center;
  gap: 16px;
  background: var(--color-card);
  border: 1px solid var(--color-line);
  border-radius: var(--radius-card);
  padding: 16px 20px;
  margin: 0 0 32px;
}

.disclosure p { margin: 0; color: var(--color-bolt); font-size: 15px; }

.in-content { margin: 32px auto; }

/* ---- news (task-4): sources list at the foot of a page, and the
   newsrow byline that repeats a page's first source on the index ---- */

.newsrow .byline { margin-top: 8px; }

.sources {
  margin: 32px 0 0;
  padding-top: 24px;
  border-top: 1px solid var(--color-line);
}

.sources ul {
  margin: 8px 0 0;
  padding: 0;
}

.sources li {
  list-style: none;
  padding: 8px 0;
  border-top: 1px solid var(--color-line);
  font-size: 14px;
  color: var(--color-bolt);
}

.sources li:first-child { border-top: 0; padding-top: 0; }
.sources li a { color: var(--color-plate); font-weight: 600; }

/* ---- author card (task-11b): the byline's own author, at the foot of
   an article or news page (_author.html) and at the top of that
   author's own /authors/<slug>/ page. ---- */

.author-card {
  display: flex;
  gap: 16px;
  align-items: flex-start;
  margin: 32px 0;
}

.author-photo {
  flex: none;
  width: 96px;
  height: 96px;
  border-radius: 50%;
  overflow: hidden;
}

.author-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.author-name { margin: 0; font-family: var(--font-display); font-weight: 600; font-size: 18px; }
.author-name a { color: var(--color-plate); }
.author-role { margin: 2px 0 0; font-size: 13px; color: var(--color-bolt); }
.author-bio { margin-top: 10px; color: var(--color-plate-soft); }
.author-bio p { margin: 0; }
.author-links { margin: 10px 0 0; display: flex; gap: 16px; flex-wrap: wrap; font-size: 13px; }
.author-links a { color: var(--color-bolt); }

/* ---- footer ---- */

.footer {
  background: var(--color-plate);
  color: var(--color-faint);
  padding-block: 40px;
  margin-top: 48px;
  font-size: 14px;
}

.footer .wordmark { display: block; margin-bottom: 8px; }
.footer-cols { display: flex; justify-content: space-between; gap: 32px; flex-wrap: wrap; }
.footer a { color: var(--color-steel); }
/* The mailbox under the tagline, on its own line (2026-09-06). */
.footer-email { display: block; margin-top: 6px; }
.footer .newsletter-placeholder { margin-top: 2rem; margin-bottom: 0; }

/* Same reasoning as .masthead-actions above: the mockup's inline-styled
   link row, as a class, since the public CSP's style-src has no
   'unsafe-inline'. */
.footer-links {
  display: flex;
  gap: 24px;
  flex-wrap: wrap;
}

/* ---- footer legal row (task-10): a second row, below footer-cols,
   listing every legal/informational page whose slug exists (base.html
   hides one by omission when its LegalPage has not been created yet, the
   same "hide, do not 404" rule footer-links already follows for
   News/Events), plus the "Privacy choices" control -- always rendered
   once an ad provider is configured, since it doubles as the CCPA "Do Not
   Sell or Share My Personal Information" link (site.js wires its click
   to whichever consent tool the configured provider loaded). ---- */

.footer-legal {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  margin-top: 24px;
  padding-top: 24px;
  border-top: 1px solid var(--color-plate-soft);
  font-size: 13px;
}

.footer-legal a { color: var(--color-faint); }

/* task-13 section B: the postal address line, only rendered while
   ORG_STREET_ADDRESS is set (base.html). */
.footer-address { margin-top: 16px; font-size: 13px; }
.footer-address address { font-style: normal; }

.privacy-choices {
  background: none;
  border: 1px solid var(--color-bolt);
  color: var(--color-faint);
  border-radius: var(--radius-control);
  padding: 4px 10px;
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}

.privacy-choices:hover,
.privacy-choices:focus-visible { border-color: var(--color-faint); }

/* ---- legal pages (task-10): the staff-only placeholder notice and the
   in-page table of contents legal_page.html renders above its body. ---- */

.legal-notice {
  display: flex;
  align-items: flex-start;
  gap: 16px;
  background: var(--color-danger-tint);
  border: 1px solid var(--color-danger);
  border-radius: var(--radius-card);
  padding: 16px 20px;
  margin: 0 0 32px;
}

.legal-notice p { margin: 0; color: var(--color-danger); font-size: 14px; }

/* ---- organization card (task-13 section B): the Contact page's own
   legal name, address, phone, and email -- content/_org_card.html. Same
   card shape as .callout/.toc above. ---- */
.org-card {
  background: var(--color-card);
  border: 1px solid var(--color-line);
  border-radius: var(--radius-card);
  padding: 20px;
  margin: 0 0 32px;
}

.org-card p,
.org-card address {
  margin: 0 0 6px;
  font-style: normal;
  font-size: 15px;
}

.org-card p:last-child,
.org-card address:last-child { margin-bottom: 0; }

.org-card-name { font-family: var(--font-display); font-weight: 600; font-size: 18px; }
.org-card a { color: var(--color-plate); }

.toc {
  background: var(--color-card);
  border: 1px solid var(--color-line);
  border-radius: var(--radius-card);
  padding: 20px;
  margin: 0 0 32px;
}

.toc ul { margin: 8px 0 0; padding: 0; columns: 2; column-gap: 24px; }
.toc li { list-style: none; padding: 4px 0; break-inside: avoid; }
.toc a { color: var(--color-plate); font-weight: 600; }

/* ---- phone (max-width: 639px): the mockup's `.phone` overrides,
   converted from a parent class into this file's own breakpoint. ---- */

@media (max-width: 639px) {
  .masthead-row { padding-block: 12px; flex-wrap: wrap; }
  .nav { width: 100%; order: 3; justify-content: space-between; gap: 8px; font-size: 14px; }
  .dateline span:last-child { display: none; }

  .ad-leaderboard_atf { width: 320px; }
  .ad[data-unit="leaderboard_atf"] { min-height: 100px; }
  .ad-adhesion {
    display: flex;
    flex-direction: row;
    gap: 12px;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    width: auto;
    z-index: 5;
    border-width: 1px 0 0;
    border-radius: 0;
    background: var(--color-card);
  }

  /* One column. A flex column rather than a plain block so the rail can
     be ordered last: in source it is the article's immediate next
     sibling (MEDIAVINE-RUNBOOK 2b), which on a phone would otherwise put
     its promo card and its 300x600 unit between the lead story and the
     card grids. */
  .front,
  .art-layout { display: flex; flex-direction: column; padding-block: 20px; }
  .front > .rail,
  .art-layout > .rail { order: 1; }
  .lead { grid-template-columns: 1fr; gap: 12px; }
  .lead-copy h2 { font-size: 30px; }
  .dek { font-size: 16px; }
  .photo-wide { min-height: 220px; }
  .grid3,
  .grid2 { grid-template-columns: 1fr; gap: 16px; margin-top: 16px; }
  .section-head { margin-top: 28px; padding-top: 16px; }
  .section-head h2 { font-size: 24px; }
  .newsrow { grid-template-columns: 72px minmax(0, 1fr); gap: 12px; }
  .event { grid-template-columns: 56px minmax(0, 1fr); }
  /* The mockup's own rule is `.phone .event .btn` (design/magazine/
     _shared.css), a single class every RSVP button in an .event row
     carries regardless of variant. This file's markup instead gives each
     button its own variant class (btn-reg, btn-plate, btn-outline --
     magazine-task-5's events use all three: "RSVP in the app", "Save a
     seat", "Remind me"), so the selector below lists all three rather
     than the one this rule originally only had (btn-outline, from
     News's pagination links, the only .btn variant that existed here
     before task-5) -- otherwise an .event row's own RSVP button, on a
     phone, would sit in the grid's auto-sized third column instead of
     dropping to its own row under the copy. */
  .event .btn-outline,
  .event .btn-reg,
  .event .btn-plate { grid-column: 2; justify-self: start; }
  .card-event { gap: 14px; }
  .art-hero h1 { font-size: 36px; }
  .measure p { font-size: 16px; }
  .measure h2 { font-size: 24px; margin-top: 28px; }
  .pull { font-size: 22px; }
  .footer { margin-top: 32px; padding-bottom: 80px; }
  .toc ul { columns: 1; }
}

/* Phones: a focused field under 16px makes iOS zoom the page (2026-09-07). */
@media (max-width: 767px) {
  input:not([type="checkbox"]):not([type="radio"]), select, textarea { font-size: max(16px, 1em); }
}
