/* Garry's List — rebrand reskin (design handoff v1, 2026-08-18).
 *
 * Loaded by the layouts via stylesheet_link_tag(Current.outlet.stylesheet),
 * after tailwind.css and application.css, so re-pointing a Tailwind theme
 * variable here reskins every utility class that reads it. That is the whole
 * trick: `text-earth`, `bg-fog` and `border-fog-dark` stay in the templates
 * and change color because the variable underneath them changed.
 *
 * Scoped to this outlet on purpose — Root Access keeps the old palette.
 *
 * The token values, their contrast ratios and the four places this diverges
 * from the handoff are in app/assets/tailwind/application.css and in the
 * admin doc at /admin/docs/brand.
 */

/* ===========================================================================
   1. The reskin — legacy names re-pointed
   =========================================================================== */
:root {
  /* Color. Left column is what the templates say; right is what it now means. */
  --color-bridge: var(--color-brand-red);         /* was #a5432e */
  --color-bridge-dark: var(--color-brand-red-hover); /* was #8a3a28 */
  --color-earth-dark: var(--color-ink);           /* was #2f2c27 */
  --color-earth: var(--color-ink-soft);           /* was #4a4840 */
  /* The handoff maps this to brand rose, with the caveat: check what it was
   * carrying, and if it was text, move it darker. It was carrying text —
   * avatar initials and secondary labels — so it takes the readable rose
   * (4.6:1) rather than the decorative one (4.3:1). */
  --color-earth-light: var(--color-brand-rose-text); /* was #6b6355 */
  --color-hills: var(--color-ink-soft);           /* was #666260 */
  --color-water: var(--color-ink-muted);          /* was #9e9a94 */
  --color-water-light: var(--color-ink-faint);    /* was #b5b0a9 */
  --color-fog: var(--color-sand);                 /* was #e2dfda — bands go from gray to warm */
  --color-fog-dark: var(--color-ink-faint);       /* was #c9c5c0 */

  /* Nothing on this site is #ffffff — everything is warm. Re-pointing
   * Tailwind's own `white` moves every `bg-white` card and every
   * `text-white` label reversed out of ink onto paper, without touching
   * the hundred templates that say `bg-white`. */
  --color-white: var(--color-paper);              /* was #ffffff */

  /* Type. Everything that was Fraunces becomes Late Serif — same job, same
   * mixed-case reading, no markup change. Balboa is the poster face and is
   * applied by name (.gl-poster*), never inherited, because it is uppercase
   * by design and would wreck any heading that was not drawn for it. */
  --font-sans: var(--font-figtree);
  --font-display: var(--font-late-serif);
  --font-poster: var(--font-balboa);

  /* Untracked caps read as a bug, and the current labels are set at about a
   * quarter of the tracking this system uses. Re-pointing Tailwind's own
   * tracking scale upgrades every existing `tracking-wide` caps label at once
   * — the cheapest and most visible half of the rebrand. */
  --tracking-wide: 0.08em;   /* quiet caps: section headings, tags, bylines */
  --tracking-wider: 0.10em;  /* UI caps: buttons, metadata, eyebrows */
  --tracking-widest: 0.14em; /* poster caps: banner and masthead lettering */
}

/* The page is warm off-white, not white. */
body {
  background-color: var(--color-paper);
  color: var(--color-ink-soft);
  font-family: var(--font-figtree);
  font-weight: 500;
  /* Figtree has no ss01/ss02/cv01/cv02 — clearing the inherited setting keeps
   * the browser from doing anything surprising with unknown features. */
  font-feature-settings: normal;
}

/* Every rung below states its colour through :where(), which has zero
 * specificity. That still beats inheritance — a declaration that matches the
 * element always does — but it loses to any colour utility on the element, so
 * `text-white` on a headline over a photograph just works. Without this the
 * rung outranks the utility (both are one class, and this file loads last) and
 * silently paints ink on a dark tile.
   =========================================================================== */

/* ===========================================================================
   2. The type ladder
   ---------------------------------------------------------------------------
   Leading is barbell-shaped and there is no page-level line-height: display
   type is set TIGHTER than its own size (0.82-1.00x), reading type LOOSER
   than convention (1.50-1.78x). Both halves are the brand.

   These classes set face, weight, leading and tracking but not size. Size
   stays on the utility the template already carries, so the reskin changes
   how the page reads without moving anything.
   =========================================================================== */

/* --- Display · Balboa. Uppercase, and set tighter than its own size.
 *
 * Size stays with whatever utility the template already carries — the reskin
 * changes the face, the weight, the leading and the tracking, not the layout.
 * Uppercase lives here rather than in the string: a screen reader spells out
 * shouted text, and a reader who copies a headline should get what the editor
 * typed. --- */
.gl-poster {
  font-family: var(--font-poster);
  font-weight: 700;
  line-height: 0.92;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* The article headline — bigger, so the ratio relaxes toward 1. */
.gl-poster-article {
  font-family: var(--font-poster);
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0;
  text-transform: uppercase;
}

/* The section masthead. Uppercase Balboa has no descenders to collide, so the
 * lines can interlock and it reads as printed. */
.gl-poster-section {
  font-family: var(--font-poster);
  font-weight: 700;
  line-height: 0.82;
  letter-spacing: 0;
  text-transform: uppercase;
  /* Ink by default; the section's own color when the element carries a
   * `category-*` class — a category masthead is set in its category color. */
}

/* The one display role set loose — it wraps to 2-4 short lines in a narrow
 * rail, where sub-1.0 leading would collide. */
.gl-poster-loose {
  font-family: var(--font-poster);
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: 0.01em;
  text-transform: uppercase;
}

/* --- Headlines · Late Serif. Cards and lists, 14-20px.
 *
 * No text-transform. The handoff annotates this rung "capitalize"; CSS
 * capitalize on a database headline produces "Sf's Nonprofit Housing
 * Machine". Sentence case is an editorial rule, applied when the headline is
 * written, not a transform applied when it is displayed. --- */
.gl-serif-headline {
  font-family: var(--font-late-serif);
  font-weight: 500;
  line-height: 1.375;
  letter-spacing: 0.02em;
}

/* --- Sans display · Figtree caps --- */
.gl-eyebrow {
  font-family: var(--font-figtree);
  font-weight: 800;
  line-height: 1.22;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

/* "Most Read", "Latest", "Top Stories" — usually paired with an 18x18 ink
 * square. The square is decoration: the heading beside it already says the
 * name, so it is hidden from assistive tech rather than announced. */
.gl-section-heading {
  font-family: var(--font-figtree);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  /* Ink by default; a section's own color when the element carries a
   * `category-*` class. The square beside it always takes the base. */
  display: flex;
  align-items: center;
  gap: 12px;
}

.gl-section-heading::before {
  content: "";
  width: 0.7em;
  height: 0.7em;
  background: var(--category-base, var(--color-ink));
  flex: none;
}

/* A section header: the heading, whatever sits opposite it (a date, a "Read
 * more" link), and the hairline that closes it off.
 *
 * Rules are how this design separates things. Sections are told apart by a
 * 1px line under their heading, not by a gap — which is why the spacing below
 * a heading (16px) is tighter than the spacing above one (48px). */
.gl-section-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding-bottom: 8px;
  margin-bottom: 16px;
  border-bottom: 1px solid var(--color-ink-faint);
}

/* --- Reading · Figtree, leading above 1.5 --- */
.gl-dek {                                                /* 18 / 28 = 1.56 */
  font-family: var(--font-figtree);
  font-weight: 600;
  line-height: 1.56;
  letter-spacing: 0;
  color: var(--color-ink-muted-text);
}

.gl-excerpt {                                            /* 12 / 18 = 1.50 */
  font-family: var(--font-figtree);
  font-weight: 400;
  line-height: 1.5;
  color: var(--color-ink-soft);
}

/* --- Furniture --- */
.gl-metadata {
  font-family: var(--font-figtree);
  font-weight: 700;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--color-ink);
}

/* The handoff sets the byline in ink-faint, which is 1.9:1 on sand — and its
 * own rules say ink-faint is never text. It takes brand-rose-text instead,
 * which is the quiet accent the rose was named for. */
.gl-byline {
  font-family: var(--font-figtree);
  font-weight: 700;
  font-size: 10px;
  line-height: 14px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-brand-rose-text);
}

/* Real italic — the kit serves it, so ask for it. A synthesized oblique is
 * visibly wrong next to the real thing. */
.gl-caption {                                            /* 14 / 26 = 1.86 */
  font-family: var(--font-figtree);
  font-weight: 400;
  font-style: italic;
  font-size: 14px;
  line-height: 26px;
  letter-spacing: 0.02em;
  color: var(--color-brand-rose-text);
}

/* The standfirst under an article headline carries a short thick ink bar on
 * its left — the design's mark for "this is the summary, not the story". */
.gl-standfirst {
  border-left: 6px solid var(--color-ink);
  padding-left: 24px;
}

/* The article column is 653px at 18px Figtree — about 80 characters, exactly
 * the WCAG 1.4.8 ceiling. A ceiling, not a target: if it widens, the size
 * drops or the column narrows. */
.gl-measure {
  max-width: 653px;
}

/* Tracking tiers, for caps runs that are not one of the rungs above. */
/* A block of running text that happens to be in caps — legal boilerplate,
 * mostly. The 0.08em label tier is too much for a paragraph; the sans-label
 * tier is the right amount, and all-caps running text reads better with a
 * little tracking than with none. */
.gl-caps-block { letter-spacing: 0.03em; }

.caps-quiet { text-transform: uppercase; letter-spacing: 0.08em; }
.caps-ui { text-transform: uppercase; letter-spacing: 0.10em; }
.caps-poster { text-transform: uppercase; letter-spacing: 0.14em; }

/* ===========================================================================
   3. Category colors
   ---------------------------------------------------------------------------
   Three custom properties per section. `base` is the identity — the square,
   the chip border, the section bar. `tint` is the pastel a chip fills with on
   hover. `text` is the label.

   The handoff says base and label are always the same value. Three of the six
   are too light to read: techno 4.0:1 on sand, state 3.2:1, merit 2.3:1 — and
   merit-gold fails even the large-text threshold at every size, so setting it
   bigger does not rescue it. So the rule narrows: the base owns everything
   you look at, the text companion owns what you read, and each companion also
   clears 4.5:1 on its own hover tint so the fill cannot hide the label. On
   the other three, base and text are the same value and the rule holds as
   written.
   =========================================================================== */
.category-techno-optimism {
  --category-base: var(--color-techno-green);
  --category-tint: var(--color-techno-green-tint);
  --category-text: var(--color-techno-green-text);
}
.category-state-capacity {
  --category-base: var(--color-state-orange);
  --category-tint: var(--color-state-orange-tint);
  --category-text: var(--color-state-orange-text);
}
.category-public-safety {
  --category-base: var(--color-safety-teal);
  --category-tint: var(--color-safety-teal-tint);
  --category-text: var(--color-safety-teal-text);
}
.category-public-education {
  --category-base: var(--color-education-magenta);
  --category-tint: var(--color-education-magenta-tint);
  --category-text: var(--color-education-magenta-text);
}
.category-ca-politicians {
  --category-base: var(--color-politicians-purple);
  --category-tint: var(--color-politicians-purple-tint);
  --category-text: var(--color-politicians-purple-text);
}
.category-merit-excellence {
  --category-base: var(--color-merit-gold);
  --category-tint: var(--color-merit-gold-tint);
  --category-text: var(--color-merit-gold-text);
}

/* The label, and the 8x8 square that identifies the section. */
.gl-category-label {
  font-family: var(--font-figtree);
  font-weight: 700;
  /* Size stays on the utility the template carries — 14px on the hero, 12px in
   * the rails. Both clear AA: the text companions were derived to. */
  line-height: 1.2;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--category-text, var(--color-brand-red));
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.gl-category-label::before {
  content: "";
  width: 8px;
  height: 8px;
  background: var(--category-base, var(--color-brand-red));
  flex: none;
}

.gl-category-label:hover {
  color: var(--category-text, var(--color-brand-red));
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* ===========================================================================
   4. Buttons
   ---------------------------------------------------------------------------
   Fully rounded, uppercase Figtree bold, 6px vertical and 20px horizontal
   padding. The label's line box is pinned to its font size, which is what
   holds the pill to its 24px height — left at `normal` it grows to 29px.

   24px is exactly the WCAG 2.5.8 minimum target with nothing to spare, so
   under a thumb the pill grows to 44px. Legal on a desktop is still a bad
   target on a phone.
   =========================================================================== */
.gl-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-figtree);
  font-weight: 700;
  font-size: 12px;
  line-height: 12px;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  padding: 6px 20px;
  border-radius: var(--radius-pill);
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.gl-button--solid {
  background: var(--color-brand-red);
  border: 1px solid var(--color-brand-red);
  color: var(--color-paper);  /* 5.0:1 */
}

.gl-button--solid:hover {
  background: var(--color-brand-red-hover);
  border-color: var(--color-brand-red-hover);
}

.gl-button--outline {
  background: transparent;
  border: 1.5px solid var(--color-ink);
  color: var(--color-ink);
}

.gl-button--outline:hover {
  background: var(--color-ink);
  color: var(--color-paper);
}

/* A full-width form CTA. The design only draws small pills, but the rule is
 * "buttons are fully rounded, uppercase Figtree bold" — a form submit is a
 * button. Same treatment, stretched, with a taller target since it is the
 * primary action on the page. */
.gl-button--block {
  width: 100%;
  justify-content: center;
  padding: 12px 24px;
}

@media (pointer: coarse) {
  .gl-button {
    min-height: 44px;
    padding-block: 14px;
  }
}

/* ===========================================================================
   5. Rules, shape and photography
   =========================================================================== */

/* Every rule is 1px #cab1ab at FULL opacity — not a tinted ink, not 40% of
 * something darker. The old site set hr to 60% of fog-dark; that lands as a
 * different color, not a lighter one. */
hr,
.gl-rule {
  border: 0;
  border-top: 1px solid var(--color-ink-faint);
  opacity: 1;
}

/* Photography has square corners — at every size, in every module. Radius
 * belongs to interface chrome only. */
.prose img,
article img,
.hero-card img,
.featured-card img,
figure img {
  border-radius: 0;
}

/* Headline links inherit the rung they sit in and darken to brand red on
 * hover. Red is a darkening, so this only works on light grounds — on the
 * hero's red wedge it would land dark-red-on-red, which is why the hero
 * headline is excluded. */
.gl-headline a,
.gl-headline-compact a,
.gl-display-article a,
.gl-display-lead a {
  color: inherit;
  text-decoration: none;
}

.gl-headline a:hover,
.gl-headline-compact a:hover,
.gl-display-article a:hover,
.gl-display-lead a:hover {
  color: var(--color-brand-red);
}

/* ===========================================================================
   6. Long-form content
   ---------------------------------------------------------------------------
   .prose and .trix-content are styled in application.css against the legacy
   variables, so they reskin for free. What they cannot inherit is the new
   leading and the new heading face, which is what this section sets.
   =========================================================================== */
.prose,
.trix-content {
  max-width: 653px;
}

.prose p,
.trix-content p,
.prose li,
.trix-content li {
  font-family: var(--font-figtree);
  font-weight: 500;
  font-size: 18px;
  line-height: 32px;  /* 1.78 — the loose half of the barbell */
  color: var(--color-ink-soft);
}

/* In-article headings are the one display role set loose — they wrap to two
 * to four short lines in a narrow column, where sub-1.0 leading would collide.
 * Size is left to whatever the element already had, so a 28px article heading
 * and a 20px heading on a legal page both keep their place in the page. */
/* Long-form rhythm on the ladder. application.css sets these at 1.75rem (28px)
 * and 2.5rem (40px), neither of which is a step — 24px between paragraphs and
 * 48px above a heading are. */
.prose p,
.trix-content p,
.prose li,
.trix-content li,
.prose ul,
.prose ol,
.trix-content ul,
.trix-content ol,
.prose blockquote,
.trix-content blockquote {
  margin-bottom: 24px !important;
}

.prose h2,
.trix-content h2,
.prose h3,
.trix-content h3 {
  margin-top: 48px !important;
  margin-bottom: 16px !important;
}

.prose h2,
.trix-content h2 {
  font-family: var(--font-poster);
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  color: var(--color-ink);
}

.prose h3,
.trix-content h3 {
  font-family: var(--font-late-serif);
  font-weight: 600;
  line-height: 1.375;
  letter-spacing: 0.02em;
  color: var(--color-ink);
}

.prose blockquote,
.trix-content blockquote {
  border-left: 4px solid var(--color-brand-red);
  font-family: var(--font-figtree);
  font-style: italic;
  color: var(--color-ink-soft);
}

.prose figcaption,
.trix-content figcaption {
  font-family: var(--font-figtree);
  font-weight: 400;
  font-style: italic;
  font-size: 14px;
  line-height: 26px;
  letter-spacing: 0.02em;
  color: var(--color-brand-rose-text);
}

/* Rung colours live in the components layer so Tailwind's utilities — which
 * are in the later `utilities` layer — override them. This file is otherwise
 * unlayered, and unlayered styles beat every layered style whatever their
 * specificity, which is why `text-white` on a headline lost until now.
 * Layer beats specificity: :where() could not fix this on its own. */
@layer components {
  .gl-poster { color: var(--category-text, var(--color-ink)); }
  .gl-poster-article { color: var(--category-text, var(--color-ink)); }
  .gl-poster-section { color: var(--category-text, var(--color-ink)); }
  .gl-poster-loose { color: var(--category-text, var(--color-ink)); }
  .gl-serif-headline { color: var(--category-text, var(--color-ink)); }
  .gl-eyebrow { color: var(--category-text, var(--color-ink)); }
  .gl-section-heading { color: var(--category-text, var(--color-ink)); }
}

/* The wordmark's SVG box reserves headroom for the star, which rises above the
 * cap height. Box-centring therefore hangs the lettering low against the nav
 * links beside it — measured, the cap band centres about 7px below the menu
 * text at a 48px mark. Nudge it back toward the optical centre.
 *
 * A percentage, not a pixel value, so it holds at both logo sizes (h-8 mobile,
 * h-12 desktop) without a second magic number. */
.gl-masthead-logo {
  transform: translateY(-16%);
}
