/* --- tb-fonts --- */
/*
 * Totoong Balita — the two typefaces, served from this domain.
 *
 * Generated from the Google Fonts stylesheet and then deduplicated:
 * the files Google returns for weights 400/500/600/700 are byte for
 * byte identical, because these are variable fonts and the weight is
 * an axis inside one file rather than four separate cuts. Sixteen
 * @font-face rules therefore point at six files.
 *
 * latin-ext is kept, and it is not optional. The peso sign, U+20B1,
 * is in latin-ext and in no other subset we load - drop it and every
 * headline with a price in it renders the currency symbol in a
 * fallback face while the digits beside it stay in Newsreader.
 *
 * Dropped: cyrillic, cyrillic-ext, greek, greek-ext and vietnamese.
 * Nothing this newsroom publishes needs them, and unicode-range means
 * a browser only ever fetches the subsets a page actually uses.
 */

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('https://totoongbalita.com/wp-content/themes/totoong-balita/assets/fonts/inter-normal-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('https://totoongbalita.com/wp-content/themes/totoong-balita/assets/fonts/inter-normal-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('https://totoongbalita.com/wp-content/themes/totoong-balita/assets/fonts/inter-normal-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('https://totoongbalita.com/wp-content/themes/totoong-balita/assets/fonts/inter-normal-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('https://totoongbalita.com/wp-content/themes/totoong-balita/assets/fonts/inter-normal-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('https://totoongbalita.com/wp-content/themes/totoong-balita/assets/fonts/inter-normal-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('https://totoongbalita.com/wp-content/themes/totoong-balita/assets/fonts/inter-normal-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('https://totoongbalita.com/wp-content/themes/totoong-balita/assets/fonts/inter-normal-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Newsreader';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('https://totoongbalita.com/wp-content/themes/totoong-balita/assets/fonts/newsreader-italic-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Newsreader';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('https://totoongbalita.com/wp-content/themes/totoong-balita/assets/fonts/newsreader-italic-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('https://totoongbalita.com/wp-content/themes/totoong-balita/assets/fonts/newsreader-normal-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('https://totoongbalita.com/wp-content/themes/totoong-balita/assets/fonts/newsreader-normal-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('https://totoongbalita.com/wp-content/themes/totoong-balita/assets/fonts/newsreader-normal-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('https://totoongbalita.com/wp-content/themes/totoong-balita/assets/fonts/newsreader-normal-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('https://totoongbalita.com/wp-content/themes/totoong-balita/assets/fonts/newsreader-normal-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('https://totoongbalita.com/wp-content/themes/totoong-balita/assets/fonts/newsreader-normal-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---------------------------------------------------------------
 * Metric-matched fallbacks
 *
 * Until a webfont arrives the browser draws the next family in the
 * stack, and when it swaps the text is re-measured. If the two faces
 * are different widths the line breaks move, and everything below the
 * paragraph moves with them — which is what a reader sees as the page
 * jumping, and what Lighthouse reported as CLS 0.173 on desktop.
 *
 * Measured on the live page rather than guessed:
 *
 *   Inter      vs -apple-system   17.8% narrower
 *   Inter      vs Arial            5.7% narrower
 *   Newsreader vs Times New Roman  4.3% narrower
 *
 * -apple-system was the first fallback in the body stack, so every
 * paragraph on a Mac was being laid out 18% too narrow and then
 * reflowed. size-adjust scales the substitute so it occupies the same
 * width as the real face, and the swap becomes invisible.
 *
 * local() only, so nothing is downloaded. Where these faces do not
 * exist — most Android devices — the rule simply fails to match and
 * the stack falls through to the plain families below, exactly as it
 * did before.
 * ------------------------------------------------------------- */

@font-face {
  font-family: 'Inter Fallback';
  font-weight: 400;
  src: local('Arial'), local('Helvetica Neue'), local('Liberation Sans');
  size-adjust: 105.7%;
  ascent-override: 90%;
  descent-override: 22%;
  line-gap-override: 0%;
}

/* Inter widens with weight as well, just less than Newsreader: the
   single rule above left 600 at -1.8% and 700 at -2.8%. Small numbers,
   but they apply to every button and eyebrow on the page. */
@font-face {
  font-family: 'Inter Fallback';
  font-weight: 500 600;
  src: local('Arial'), local('Helvetica Neue'), local('Liberation Sans');
  size-adjust: 107.6%;
  ascent-override: 90%;
  descent-override: 22%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'Inter Fallback';
  font-weight: 700;
  src: local('Arial'), local('Helvetica Neue'), local('Liberation Sans');
  size-adjust: 108.7%;
  ascent-override: 90%;
  descent-override: 22%;
  line-gap-override: 0%;
}

/* One rule per weight, because a single substitute cannot follow a
 * variable font.
 *
 * Newsreader widens as it gets heavier — 732px, 771px, 791px for the
 * same headline at 400, 600 and 700. Times New Roman, loaded through
 * local(), is one static face: it measured 738px at every weight, so a
 * single size-adjust matched 400 nicely (+0.8%) and left 700 at -6.8%,
 * which is worse than the plain fallback it replaced. Headlines are
 * mostly 700, so that is the weight that matters.
 *
 * Each size-adjust below is the measured ratio for its own weight. */

@font-face {
  font-family: 'Newsreader Fallback';
  font-weight: 400;
  src: local('Times New Roman'), local('Liberation Serif'), local('Times');
  size-adjust: 103.5%;
  ascent-override: 92%;
  descent-override: 24%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'Newsreader Fallback';
  font-weight: 600;
  src: local('Times New Roman'), local('Liberation Serif'), local('Times');
  size-adjust: 109%;
  ascent-override: 92%;
  descent-override: 24%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'Newsreader Fallback';
  font-weight: 700;
  src: local('Times New Roman'), local('Liberation Serif'), local('Times');
  size-adjust: 111.8%;
  ascent-override: 92%;
  descent-override: 24%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'Newsreader Fallback';
  font-style: italic;
  font-weight: 400;
  src: local('Times New Roman Italic'), local('Liberation Serif Italic'), local('Times Italic');
  /* Italic needed its own number and in the other direction: at 103.5%
     it came out 8.3% too wide. The masthead's "News Online" is set in
     it, so this one is visible on every page. */
  size-adjust: 95.6%;
  ascent-override: 92%;
  descent-override: 24%;
  line-gap-override: 0%;
}

/* --- tb-tokens --- */
/**
 * Totoong Balita — Design Tokens
 * "Editorial Clarity" design system. Single source of truth for every
 * color, type scale, space step and structural rule on the site.
 *
 * Nothing in this file styles an element. It only declares values.
 * Component stylesheets consume these variables and never hardcode a hex,
 * a px font-size, or a rem margin.
 *
 * COLOR — SETTLED 2026-09-25.
 * DESIGN.md states its palette twice and the two disagree. We use the prose
 * sections' values, not the YAML frontmatter's Material ramp, because:
 *   1. every component spec in DESIGN.md cites the prose values by hex
 *      ("red vertical bar #c91d24", "hairline #e2e5e9", "solid #111418");
 *   2. the frontmatter's outline-variant (#e5bdb9) is pink — a generator
 *      artifact from seeding the neutral ramp off the red, and at odds with
 *      the document's own call for crisp neutral hairlines;
 *   3. the frontmatter's surface (#f8f9ff) is blue-tinted, where the prose
 *      asks for "#ffffff as the pure paper default".
 * The frontmatter ramp is kept at the bottom as --tb-m3-* for reference only.
 * Reviewed against both renderings and confirmed; don't silently reopen this.
 */

:root {
	/* ---------------------------------------------------------------
	 * BRAND
	 * ------------------------------------------------------------- */
	--tb-primary:              #c91d24;  /* Editorial Red — breaking, category pips, section rules */
	--tb-primary-dark:         #a20013;  /* Pressed / hover state for red surfaces */
	--tb-on-primary:           #ffffff;
	--tb-primary-tint:         #fdeced;  /* Faint red wash — alert row backgrounds */

	--tb-secondary:            #0f3b82;  /* Deep Broadcast Navy — civic, institutional, links */
	--tb-secondary-dark:       #0a2a5e;
	--tb-on-secondary:         #ffffff;
	--tb-secondary-tint:       #eaf0fa;

	--tb-tertiary:             #1b74e4;  /* Electric Cobalt — interactive states, active tabs */
	--tb-tertiary-dark:        #145ab4;
	--tb-on-tertiary:          #ffffff;

	/* ---------------------------------------------------------------
	 * INK — text colors, densest to lightest
	 * ------------------------------------------------------------- */
	--tb-ink:                  #111418;  /* Deep Newsroom Charcoal — headlines, body */
	--tb-ink-strong:           #000000;
	--tb-ink-muted:            #464c54;  /* Decks, excerpts, secondary copy */
	--tb-ink-subtle:           #616770;  /* Timestamps, bylines, captions */
	--tb-ink-faint:            #8b9199;  /* Disabled, placeholder */
	--tb-ink-inverse:          #ffffff;  /* Text on dark/red bands */
	--tb-ink-inverse-muted:    rgba(255, 255, 255, 0.72);

	/* ---------------------------------------------------------------
	 * SURFACE — backgrounds, densest to lightest
	 * ------------------------------------------------------------- */
	--tb-surface:              #ffffff;  /* Pure paper — the default canvas */
	--tb-surface-sunken:       #f8f9fa;  /* Secondary story wells, utility trays, tables */
	--tb-surface-muted:        #f1f3f5;  /* Hover fills, input backgrounds */
	--tb-surface-inverse:      #111418;  /* Dark header bands, footer */
	--tb-surface-inverse-alt:  #1c2026;  /* Raised block inside a dark band */

	/* ---------------------------------------------------------------
	 * STRUCTURE — the hairline grid. No shadows anywhere.
	 * ------------------------------------------------------------- */
	--tb-border:               #e2e5e9;  /* Soft boundary — the default rule */
	--tb-border-strong:        #cbd0d6;  /* Category dividers, input perimeters */
	--tb-border-inverse:       rgba(255, 255, 255, 0.16);
	--tb-rule:                 1px solid var(--tb-border);
	--tb-rule-strong:          1px solid var(--tb-border-strong);
	--tb-rule-inverse:         1px solid var(--tb-border-inverse);

	/* Status */
	--tb-error:                #ba1a1a;
	--tb-error-tint:           #ffdad6;
	--tb-success:              #0f7b3f;
	--tb-success-tint:         #e3f5ea;
	--tb-warning:              #a35a00;
	--tb-warning-tint:         #fdf0e0;

	/* ---------------------------------------------------------------
	 * CATEGORY ACCENTS
	 * Per DESIGN.md: red for news, navy for business, neutral for
	 * lifestyle/culture. Sections pick one via the --tb-accent hook.
	 * ------------------------------------------------------------- */
	--tb-accent:               var(--tb-primary);
	--tb-accent-news:          #c91d24;
	--tb-accent-politics:      #0f3b82;
	--tb-accent-business:      #0f3b82;
	--tb-accent-infra:         #1b74e4;
	--tb-accent-environment:   #0f7b3f;
	--tb-accent-sports:        #a35a00;
	--tb-accent-lifestyle:     #464c54;
	--tb-accent-culture:       #464c54;

	/* ---------------------------------------------------------------
	 * TYPEFACES
	 * Newsreader = narrative authority. Inter = speed and UI utility.
	 * ------------------------------------------------------------- */
	/* The Fallback families are metric-matched stand-ins defined in
	   tb-fonts.css. They sit second so the text is the right width
	   before the webfont lands, which is what stops the page jumping
	   when it does. The plain families stay behind them for platforms
	   where the local() source does not exist. */
	--tb-font-headline: "Newsreader", "Newsreader Fallback", "Times New Roman", Georgia, serif;
	--tb-font-body: "Inter", "Inter Fallback", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
	--tb-font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;

	/* ---------------------------------------------------------------
	 * TYPE SCALE
	 * Each role ships size / line-height / weight / tracking as four
	 * variables so a component can apply a role in one place. The
	 * `tb-t-*` utility classes in tb-base.css bundle them.
	 * ------------------------------------------------------------- */

	/* display-hero — the single lead story on a front page */
	--tb-display-hero-size: 3rem;          /* 48px */
	--tb-display-hero-line: 3.375rem;      /* 54px */
	--tb-display-hero-weight: 700;
	--tb-display-hero-track: -0.02em;

	/* headline-lg — section leads, single-post titles */
	--tb-headline-lg-size: 2rem;           /* 32px */
	--tb-headline-lg-line: 2.375rem;       /* 38px */
	--tb-headline-lg-weight: 700;
	--tb-headline-lg-track: -0.015em;

	/* headline-md — secondary features */
	--tb-headline-md-size: 1.375rem;       /* 22px */
	--tb-headline-md-line: 1.75rem;        /* 28px */
	--tb-headline-md-weight: 600;
	--tb-headline-md-track: -0.005em;

	/* headline-sm — grid cards, compact rows */
	--tb-headline-sm-size: 1.125rem;       /* 18px */
	--tb-headline-sm-line: 1.5rem;         /* 24px */
	--tb-headline-sm-weight: 600;
	--tb-headline-sm-track: 0;

	/* subhead — decks under a hero headline */
	--tb-subhead-size: 1rem;               /* 16px */
	--tb-subhead-line: 1.5rem;             /* 24px */
	--tb-subhead-weight: 500;

	/* body-lg — article running text */
	--tb-body-lg-size: 1.125rem;           /* 18px */
	--tb-body-lg-line: 1.875rem;           /* 30px */
	--tb-body-lg-weight: 400;

	/* body-md — card excerpts, default UI copy */
	--tb-body-md-size: 0.9375rem;          /* 15px */
	--tb-body-md-line: 1.4375rem;          /* 23px */
	--tb-body-md-weight: 400;

	/* body-sm — dense listings, secondary excerpts */
	--tb-body-sm-size: 0.8125rem;          /* 13px */
	--tb-body-sm-line: 1.1875rem;          /* 19px */
	--tb-body-sm-weight: 400;

	/* label-category — uppercase section and category markers */
	--tb-label-size: 0.6875rem;            /* 11px */
	--tb-label-line: 0.875rem;             /* 14px */
	--tb-label-weight: 700;
	--tb-label-track: 0.08em;

	/* timestamp — relative times, bylines */
	--tb-timestamp-size: 0.75rem;          /* 12px */
	--tb-timestamp-line: 1rem;             /* 16px */
	--tb-timestamp-weight: 400;

	/* caption — photo credits, fine print */
	--tb-caption-size: 0.75rem;            /* 12px */
	--tb-caption-line: 1.0625rem;          /* 17px */
	--tb-caption-weight: 400;

	/* ---------------------------------------------------------------
	 * SPACING — 4px base rhythm
	 * ------------------------------------------------------------- */
	--tb-space-xxs: 0.25rem;   /*  4px */
	--tb-space-xs:  0.5rem;    /*  8px */
	--tb-space-sm:  0.75rem;   /* 12px */
	--tb-space-md:  1rem;      /* 16px */
	--tb-space-lg:  1.5rem;    /* 24px */
	--tb-space-xl:  2rem;      /* 32px */
	--tb-space-2xl: 3rem;      /* 48px */
	--tb-space-3xl: 4.5rem;    /* 72px */

	/* ---------------------------------------------------------------
	 * LAYOUT
	 * ------------------------------------------------------------- */
	--tb-container-max: 1280px;
	--tb-gutter: 1rem;              /* mobile page margin; bumped at >=1024px */
	--tb-grid-gap: 1rem;            /* card-to-card gap; bumped at >=1024px */
	--tb-section-gap: 3rem;         /* vertical space between homepage sections */
	--tb-measure: 68ch;             /* max line length for article body copy */

	/* ---------------------------------------------------------------
	 * SHAPE — strict sharp geometry. Circles are the only exception,
	 * reserved for live pips and author avatars.
	 * ------------------------------------------------------------- */
	--tb-radius: 0;
	--tb-radius-pill: 9999px;
	--tb-radius-circle: 50%;

	/* Media aspect ratios */
	--tb-ratio-hero: 16 / 9;
	--tb-ratio-card: 16 / 10;
	--tb-ratio-square: 1 / 1;
	--tb-ratio-portrait: 3 / 4;

	/* ---------------------------------------------------------------
	 * MOTION — restrained. Images scale, headlines recolor, nothing lifts.
	 * ------------------------------------------------------------- */
	--tb-ease: cubic-bezier(0.2, 0, 0.2, 1);
	--tb-duration-fast: 150ms;
	--tb-duration: 300ms;
	--tb-duration-slow: 500ms;
	--tb-media-hover-scale: 1.04;
	--tb-media-hover-scale-lead: 1.02;

	/* Overlay gradient for text sitting on photography (WCAG AAA) */
	--tb-media-scrim: linear-gradient(180deg, rgba(0, 0, 0, 0) 40%, rgba(17, 20, 24, 0.85) 100%);

	/* Focus ring — visible, squared, no outer glow.
	 * currentColor, not a fixed hue: the ring takes the colour of whatever it
	 * surrounds, so it is ink on paper and light on the dark footer and drawer
	 * without a single per-component override. It was --tb-tertiary (Electric
	 * Cobalt) — the one blue on an otherwise red-and-ink site, which read as a
	 * stray browser artifact rather than as part of the design.
	 *
	 * 1px at 1px offset, not 2px at 2px. Tabbed through BBC, NPR, Rappler,
	 * Inquirer, Philstar and GMA: every one of them that draws a ring draws it
	 * at 1px, and the four running the browser default sit at 1px offset 1px.
	 * A 2px ring held 2px off the element reads as a detached box floating
	 * around things — that, not the colour alone, was what looked wrong.
	 * This traces the element instead of boxing it.
	 * Do not replace this with `none`: see tb-base.css for why. */
	--tb-focus-color: currentColor;
	--tb-focus-ring: 1px solid currentColor;
	--tb-focus-offset: 1px;

	/* Stacking order */
	--tb-z-base: 1;
	--tb-z-sticky: 100;
	--tb-z-header: 200;
	--tb-z-drawer: 300;
	--tb-z-modal: 400;
	--tb-z-toast: 500;

	/* Measured at runtime by tb-header.js so sections can offset for the
	   fixed masthead without hardcoding its height. */
	--tb-header-height: 0px;   /* full masthead — set by tb-ui.js */
	--tb-header-sticky: 0px;   /* condensed scroll bar — set by tb-ui.js */
}

/* Desktop: wider gutters and grid gaps per DESIGN.md's 12-col spec. */
@media (min-width: 1024px) {
	:root {
		--tb-gutter: 1.5rem;
		--tb-grid-gap: 1.5rem;
		--tb-section-gap: 4rem;
	}
}

/* Mobile type: hero and large headlines step down one rung. */
@media (max-width: 767px) {
	:root {
		--tb-display-hero-size: 1.875rem;   /* 30px */
		--tb-display-hero-line: 2.25rem;    /* 36px */
		--tb-display-hero-track: -0.015em;

		--tb-headline-lg-size: 1.5rem;      /* 24px */
		--tb-headline-lg-line: 1.875rem;    /* 30px */
		--tb-headline-lg-track: -0.01em;

		--tb-headline-md-size: 1.25rem;     /* 20px */
		--tb-headline-md-line: 1.625rem;    /* 26px */

		--tb-body-lg-size: 1.0625rem;       /* 17px */
		--tb-body-lg-line: 1.75rem;         /* 28px */
	}
}

@media (prefers-reduced-motion: reduce) {
	:root {
		--tb-duration-fast: 0ms;
		--tb-duration: 0ms;
		--tb-duration-slow: 0ms;
		--tb-media-hover-scale: 1;
		--tb-media-hover-scale-lead: 1;
	}
}

/* -------------------------------------------------------------------
 * ALTERNATE PALETTE — DESIGN.md YAML frontmatter (Material ramp).
 * This is what code.html compiles to. Unused by default; to adopt it,
 * remap the brand/ink/surface tokens above to these values.
 * ----------------------------------------------------------------- */
:root {
	--tb-m3-primary:            #a20013;
	--tb-m3-primary-container:  #c91d24;
	--tb-m3-secondary:          #395ca4;
	--tb-m3-tertiary:           #004c9f;
	--tb-m3-surface:            #f8f9ff;
	--tb-m3-surface-container:  #eceef3;
	--tb-m3-surface-highest:    #e1e2e8;
	--tb-m3-on-surface:         #191c20;
	--tb-m3-on-surface-variant: #5c403d;
	--tb-m3-outline:            #906f6c;
	--tb-m3-outline-variant:    #e5bdb9;
}

/* --- tb-base --- */
/**
 * Totoong Balita — Base Layer
 * Reset, document defaults, typography roles, layout primitives.
 * Consumes tb-tokens.css. Declares no color or size of its own.
 */

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

html {
	-webkit-text-size-adjust: 100%;
	scroll-behavior: smooth;
	/* Anchored jumps clear the fixed masthead */
	/* The condensed bar, not the full masthead: by the time an anchor
	   jump lands you are scrolled, so the condensed band is what covers
	   the target. Falls back to the full height before tb-ui.js runs. */
	scroll-padding-top: calc(var(--tb-header-sticky, var(--tb-header-height)) + var(--tb-space-md));
}

body {
	margin: 0;
	background: var(--tb-surface);
	color: var(--tb-ink);
	font-family: var(--tb-font-body);
	font-size: var(--tb-body-md-size);
	line-height: var(--tb-body-md-line);
	font-weight: var(--tb-body-md-weight);
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
ul, ol { margin: 0; padding: 0; }
ul[class], ol[class] { list-style: none; }

img, picture, video, canvas, svg {
	display: block;
	max-width: 100%;
}
img { height: auto; border-style: none; }

input, button, textarea, select {
	font: inherit;
	color: inherit;
}
button { background: none; border: none; padding: 0; cursor: pointer; }

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

table { border-collapse: collapse; width: 100%; }

hr {
	border: none;
	border-top: var(--tb-rule);
	margin: var(--tb-space-lg) 0;
}

/* Keyboard-only by design. :focus-visible means a mouse click never draws a
 * ring — only Tab, arrow keys and other keyboard entry do — and the second
 * rule clears the ring for anything that still reports :focus after a click.
 * The ring itself is currentColor (see tb-tokens.css), not cobalt.
 * This is not decoration: without it nobody navigating by keyboard can tell
 * where they are, which includes newsroom staff working through the editor
 * and the post list. Retone it, move it, inset it — but leave it visible. */
:focus-visible {
	outline: var(--tb-focus-ring);
	outline-offset: var(--tb-focus-offset);
}
:focus:not(:focus-visible) { outline: none; }

::selection {
	background: var(--tb-primary);
	color: var(--tb-on-primary);
}

/* -------------------------------------------------------------------
 * TYPOGRAPHY ROLES
 * Apply a role with one class. These are the only places the type
 * scale is assembled; components reference the class or @extend the
 * same four variables.
 * ----------------------------------------------------------------- */
.tb-t-display {
	font-family: var(--tb-font-headline);
	font-size: var(--tb-display-hero-size);
	line-height: var(--tb-display-hero-line);
	font-weight: var(--tb-display-hero-weight);
	letter-spacing: var(--tb-display-hero-track);
}

.tb-t-headline-lg {
	font-family: var(--tb-font-headline);
	font-size: var(--tb-headline-lg-size);
	line-height: var(--tb-headline-lg-line);
	font-weight: var(--tb-headline-lg-weight);
	letter-spacing: var(--tb-headline-lg-track);
}

.tb-t-headline-md {
	font-family: var(--tb-font-headline);
	font-size: var(--tb-headline-md-size);
	line-height: var(--tb-headline-md-line);
	font-weight: var(--tb-headline-md-weight);
	letter-spacing: var(--tb-headline-md-track);
}

.tb-t-headline-sm {
	font-family: var(--tb-font-headline);
	font-size: var(--tb-headline-sm-size);
	line-height: var(--tb-headline-sm-line);
	font-weight: var(--tb-headline-sm-weight);
}

.tb-t-subhead {
	font-family: var(--tb-font-body);
	font-size: var(--tb-subhead-size);
	line-height: var(--tb-subhead-line);
	font-weight: var(--tb-subhead-weight);
}

.tb-t-body-lg {
	font-family: var(--tb-font-body);
	font-size: var(--tb-body-lg-size);
	line-height: var(--tb-body-lg-line);
}

.tb-t-body {
	font-family: var(--tb-font-body);
	font-size: var(--tb-body-md-size);
	line-height: var(--tb-body-md-line);
}

.tb-t-body-sm {
	font-family: var(--tb-font-body);
	font-size: var(--tb-body-sm-size);
	line-height: var(--tb-body-sm-line);
}

.tb-t-label {
	font-family: var(--tb-font-body);
	font-size: var(--tb-label-size);
	line-height: var(--tb-label-line);
	font-weight: var(--tb-label-weight);
	letter-spacing: var(--tb-label-track);
	text-transform: uppercase;
}

.tb-t-timestamp {
	font-family: var(--tb-font-body);
	font-size: var(--tb-timestamp-size);
	line-height: var(--tb-timestamp-line);
	font-weight: var(--tb-timestamp-weight);
	color: var(--tb-ink-subtle);
}

.tb-t-caption {
	font-family: var(--tb-font-body);
	font-size: var(--tb-caption-size);
	line-height: var(--tb-caption-line);
	color: var(--tb-ink-subtle);
}

/* Editorial distinction — analysis, opinion, exclusives */
.tb-t-italic { font-style: italic; font-weight: 400; }

/* -------------------------------------------------------------------
 * LAYOUT PRIMITIVES
 * ----------------------------------------------------------------- */

/* The page container. Every full-width band puts one of these inside. */
.tb-container {
	width: 100%;
	max-width: var(--tb-container-max);
	margin-inline: auto;
	padding-inline: var(--tb-gutter);
}

/* A full-bleed band that still aligns its contents to the container. */
.tb-band { width: 100%; }
.tb-band--sunken { background: var(--tb-surface-sunken); }
.tb-band--inverse { background: var(--tb-surface-inverse); color: var(--tb-ink-inverse); }
.tb-band--ruled { border-block: var(--tb-rule); }

/* Vertical rhythm between homepage sections. */
.tb-section { margin-bottom: var(--tb-section-gap); }
.tb-section:last-child { margin-bottom: 0; }

/* Article measure — caps line length for sustained reading. */
.tb-measure { max-width: var(--tb-measure); }

/* --- Grid ---------------------------------------------------------
 * 12 columns on desktop, 8 on tablet, 4 on mobile, matching DESIGN.md.
 * Children opt into spans with .tb-col-{n} / .tb-col-md-{n}.
 * ----------------------------------------------------------------- */
.tb-grid {
	display: grid;
	gap: var(--tb-grid-gap);
	grid-template-columns: repeat(4, minmax(0, 1fr));
}

@media (min-width: 768px) {
	.tb-grid { grid-template-columns: repeat(8, minmax(0, 1fr)); }
}
@media (min-width: 1024px) {
	.tb-grid { grid-template-columns: repeat(12, minmax(0, 1fr)); }
}

/* Mobile spans (4-col base) */
.tb-col-1 { grid-column: span 1; }
.tb-col-2 { grid-column: span 2; }
.tb-col-3 { grid-column: span 3; }
.tb-col-4 { grid-column: span 4; }

/* Tablet spans (8-col) */
@media (min-width: 768px) {
	.tb-col-md-2 { grid-column: span 2; }
	.tb-col-md-3 { grid-column: span 3; }
	.tb-col-md-4 { grid-column: span 4; }
	.tb-col-md-5 { grid-column: span 5; }
	.tb-col-md-6 { grid-column: span 6; }
	.tb-col-md-8 { grid-column: span 8; }
}

/* Desktop spans (12-col) */
@media (min-width: 1024px) {
	.tb-col-lg-2  { grid-column: span 2; }
	.tb-col-lg-3  { grid-column: span 3; }
	.tb-col-lg-4  { grid-column: span 4; }
	.tb-col-lg-5  { grid-column: span 5; }
	.tb-col-lg-6  { grid-column: span 6; }
	.tb-col-lg-7  { grid-column: span 7; }
	.tb-col-lg-8  { grid-column: span 8; }
	.tb-col-lg-9  { grid-column: span 9; }
	.tb-col-lg-12 { grid-column: span 12; }
}

/* --- Equal-width card matrices ------------------------------------
 * For the common "N cards across" case where 12-col spans are overkill.
 * ----------------------------------------------------------------- */
.tb-cards {
	display: grid;
	gap: var(--tb-grid-gap);
	grid-template-columns: 1fr;
}
@media (min-width: 640px) {
	.tb-cards--2 > *, .tb-cards--3 > *, .tb-cards--4 > * { min-width: 0; }
	.tb-cards--2, .tb-cards--3, .tb-cards--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1024px) {
	.tb-cards--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
	.tb-cards--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* --- Stack: vertical flow with a consistent gap -------------------- */
.tb-stack { display: flex; flex-direction: column; gap: var(--tb-space-md); }
.tb-stack--xs { gap: var(--tb-space-xs); }
.tb-stack--sm { gap: var(--tb-space-sm); }
.tb-stack--lg { gap: var(--tb-space-lg); }

/* --- Cluster: horizontal group that wraps -------------------------- */
.tb-cluster {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--tb-space-xs);
}
.tb-cluster--sm { gap: var(--tb-space-sm); }
.tb-cluster--md { gap: var(--tb-space-md); }
.tb-cluster--between { justify-content: space-between; flex-wrap: nowrap; }

/* Vertical reading lanes — the optional 1px column rule from DESIGN.md */
.tb-lane + .tb-lane { border-left: var(--tb-rule); padding-left: var(--tb-grid-gap); }
@media (max-width: 1023px) {
	.tb-lane + .tb-lane { border-left: none; padding-left: 0; }
}

/* -------------------------------------------------------------------
 * UTILITIES
 * ----------------------------------------------------------------- */

/* Truncate to N lines. The workhorse for headlines and excerpts. */
.tb-clamp-1, .tb-clamp-2, .tb-clamp-3, .tb-clamp-4 {
	display: -webkit-box;
	-webkit-box-orient: vertical;
	overflow: hidden;
}
/* The [hidden] attribute must actually hide.
 *
 * Any display: declaration outranks the UA stylesheet's
 * [hidden] { display: none }, so an element styled as flex or grid stays
 * on screen no matter how many times a script sets .hidden = true. The
 * newsroom's upload progress bar sat visible at 0% for exactly this
 * reason. One !important here is worth the alternative, which is
 * remembering to write a :not([hidden]) guard on every flex component
 * anyone ever adds. */
[hidden] { display: none !important; }

.tb-clamp-1 { -webkit-line-clamp: 1; }
.tb-clamp-2 { -webkit-line-clamp: 2; }
.tb-clamp-3 { -webkit-line-clamp: 3; }
.tb-clamp-4 { -webkit-line-clamp: 4; }

.tb-muted  { color: var(--tb-ink-muted); }
.tb-subtle { color: var(--tb-ink-subtle); }

.tb-hide { display: none !important; }
@media (max-width: 639px)  { .tb-hide-sm  { display: none !important; } }
@media (max-width: 767px)  { .tb-hide-mob { display: none !important; } }
@media (max-width: 1023px) { .tb-hide-tab { display: none !important; } }
@media (min-width: 1024px) { .tb-hide-desk { display: none !important; } }

/* Screen-reader only, with a visible skip-link variant. */
.tb-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;
}
.tb-skip-link {
	position: absolute;
	top: 0; left: 0;
	z-index: var(--tb-z-toast);
	transform: translateY(-120%);
	background: var(--tb-surface-inverse);
	color: var(--tb-ink-inverse);
	padding: var(--tb-space-xs) var(--tb-space-md);
	font-size: var(--tb-body-sm-size);
	font-weight: 600;
	transition: transform var(--tb-duration-fast) var(--tb-ease);
}
.tb-skip-link:focus { transform: translateY(0); }

/* --- tb-components --- */
/**
 * Totoong Balita — Component Library
 * Every reusable element on the site: section headers, story cards,
 * badges, buttons, inputs, banners, pagination.
 *
 * Rule of the house: a new page composes these classes. It does not
 * write new card or button CSS. If a page needs a variant, the variant
 * is added here as a modifier so every page gets it.
 */

/* ===================================================================
 * 1. SECTION HEADER  —  .tb-section-head
 * Red vertical bar + uppercase title, closed by a full-width rule.
 * Recolor per section with --tb-accent.
 * ================================================================= */
.tb-section-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--tb-space-sm) var(--tb-space-md);
	flex-wrap: wrap;
	padding-bottom: var(--tb-space-xs);
	margin-bottom: var(--tb-space-md);
	border-bottom: var(--tb-rule);
}

/* The live/"see all" affordance keeps to one line and never wraps
   mid-phrase next to the title. */
.tb-section-head > .tb-cluster,
.tb-section-head__link { flex-shrink: 0; white-space: nowrap; }

.tb-section-head__group {
	display: flex;
	align-items: center;
	gap: var(--tb-space-xs);
	min-width: 0;
}

/* The 3px accent bar that anchors every section title. */
.tb-section-head__bar {
	flex-shrink: 0;
	width: 3px;
	height: 1.25rem;
	background: var(--tb-accent);
}

.tb-section-head__title {
	font-family: var(--tb-font-body);
	font-size: var(--tb-label-size);
	line-height: var(--tb-label-line);
	font-weight: var(--tb-label-weight);
	letter-spacing: var(--tb-label-track);
	text-transform: uppercase;
	color: var(--tb-ink);
}

.tb-section-head__note {
	font-size: var(--tb-caption-size);
	line-height: var(--tb-caption-line);
	color: var(--tb-ink-subtle);
	padding-left: var(--tb-space-xs);
}

.tb-section-head__link {
	display: inline-flex;
	align-items: center;
	gap: var(--tb-space-xxs);
	flex-shrink: 0;
	font-size: var(--tb-caption-size);
	font-weight: 600;
	color: var(--tb-primary);
	transition: color var(--tb-duration-fast) var(--tb-ease);
}
.tb-section-head__link:hover { color: var(--tb-primary-dark); text-decoration: underline; }
.tb-section-head__link svg { width: 14px; height: 14px; }

/* Section accent presets — set on the section, inherited by the bar. */
.tb-accent-news       { --tb-accent: var(--tb-accent-news); }
.tb-accent-politics   { --tb-accent: var(--tb-accent-politics); }
.tb-accent-business   { --tb-accent: var(--tb-accent-business); }
.tb-accent-infra      { --tb-accent: var(--tb-accent-infra); }
.tb-accent-environment{ --tb-accent: var(--tb-accent-environment); }
.tb-accent-sports     { --tb-accent: var(--tb-accent-sports); }
.tb-accent-lifestyle  { --tb-accent: var(--tb-accent-lifestyle); }
/* Showbiz has carried the "culture" accent since it was seeded and the token
   has always existed, but this rule did not — the class landed on the markup
   and resolved to nothing. Featured uses it too. */
.tb-accent-culture    { --tb-accent: var(--tb-accent-culture); }

/* ===================================================================
 * 2. LIVE PIP  —  .tb-pip
 * The pulsing dot. One of the two sanctioned circles in the system.
 * ================================================================= */
.tb-pip {
	display: inline-block;
	flex-shrink: 0;
	width: 8px;
	height: 8px;
	border-radius: var(--tb-radius-circle);
	background: var(--tb-primary);
	animation: tb-pulse 2s var(--tb-ease) infinite;
}
.tb-pip--sm { width: 6px; height: 6px; }
.tb-pip--light { background: var(--tb-ink-inverse); }

@keyframes tb-pulse {
	0%, 100% { opacity: 1; }
	50%      { opacity: 0.35; }
}
@media (prefers-reduced-motion: reduce) {
	.tb-pip { animation: none; }
}

/* ===================================================================
 * 3. BADGES & EYEBROWS  —  .tb-badge / .tb-eyebrow
 * Eyebrow = unfilled category marker above a headline (the default).
 * Badge   = filled marker, for overlays and breaking stories.
 * ================================================================= */
.tb-eyebrow {
	display: inline-block;
	font-family: var(--tb-font-body);
	font-size: var(--tb-label-size);
	line-height: var(--tb-label-line);
	font-weight: var(--tb-label-weight);
	letter-spacing: var(--tb-label-track);
	text-transform: uppercase;
	color: var(--tb-accent);
	transition: color var(--tb-duration-fast) var(--tb-ease);
}
a.tb-eyebrow:hover { color: var(--tb-primary-dark); }

.tb-badge {
	display: inline-flex;
	align-items: center;
	gap: var(--tb-space-xxs);
	padding: 0.1875rem var(--tb-space-xs);
	background: var(--tb-accent);
	color: var(--tb-on-primary);
	border-radius: var(--tb-radius);
	font-family: var(--tb-font-body);
	font-size: var(--tb-label-size);
	line-height: var(--tb-label-line);
	font-weight: var(--tb-label-weight);
	letter-spacing: var(--tb-label-track);
	text-transform: uppercase;
	white-space: nowrap;
}
.tb-badge--navy    { background: var(--tb-secondary); }
.tb-badge--cobalt  { background: var(--tb-tertiary); }
.tb-badge--neutral { background: var(--tb-ink); }
.tb-badge--outline {
	background: transparent;
	color: var(--tb-accent);
	border: 1px solid currentColor;
}

/* -------------------------------------------------------------------
 * BREAKING / LIVE FLAG  —  .tb-flag
 * Sits in .tb-card__kicker beside the category eyebrow. Always red,
 * never the section accent: a sports story that is breaking is
 * breaking, and inheriting --tb-accent would print it in bronze.
 * ----------------------------------------------------------------- */
.tb-card__kicker {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--tb-space-xs);
	min-width: 0;
}

.tb-flag {
	display: inline-flex;
	align-items: center;
	gap: var(--tb-space-xxs);
	flex-shrink: 0;
	font-family: var(--tb-font-body);
	font-size: var(--tb-label-size);
	line-height: var(--tb-label-line);
	font-weight: var(--tb-label-weight);
	letter-spacing: var(--tb-label-track);
	text-transform: uppercase;
	white-space: nowrap;
}

/* Solid, for the lead and the article header. */
.tb-flag--pill {
	padding: 0.1875rem var(--tb-space-xs);
	background: var(--tb-primary);
	color: var(--tb-on-primary);
	border-radius: var(--tb-radius);
}

/* Quieter, for stacked lists. Five solid pills down the side of the
   lead would out-shout the lead they sit beside. */
.tb-flag--rule {
	padding-left: var(--tb-space-xs);
	border-left: 2px solid var(--tb-primary);
	color: var(--tb-primary);
}

/* The LIVE pip is white for the solid pill. On the rule form there is
   no red behind it, so it takes the text colour instead of vanishing. */
.tb-flag--rule .tb-pip { background: currentColor; }

/* ===================================================================
 * 4. META ROW  —  .tb-meta
 * Byline • timestamp • bureau, separated by interpuncts.
 * ================================================================= */
.tb-meta {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--tb-space-xs);
	font-size: var(--tb-timestamp-size);
	line-height: var(--tb-timestamp-line);
	color: var(--tb-ink-subtle);
}
.tb-meta__author { font-weight: 500; color: var(--tb-ink); }
.tb-meta__bureau { color: var(--tb-tertiary); }
.tb-meta__sep { color: var(--tb-border-strong); }

/* ===================================================================
 * 5. MEDIA FRAME  —  .tb-media
 * Overflow-hidden box that crops to a ratio and scales its image on
 * hover. Depth comes from the crop, never from a shadow.
 * ================================================================= */
.tb-media {
	position: relative;
	display: block;
	overflow: hidden;
	background: var(--tb-surface-muted);
	aspect-ratio: var(--tb-ratio-card);
}
.tb-media--hero    { aspect-ratio: var(--tb-ratio-hero); }
.tb-media--square  { aspect-ratio: var(--tb-ratio-square); }
.tb-media--portrait{ aspect-ratio: var(--tb-ratio-portrait); }

.tb-media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform var(--tb-duration) var(--tb-ease);
}

/* Scrim for headlines laid over photography. */
.tb-media__scrim {
	position: absolute;
	inset: 0;
	background: var(--tb-media-scrim);
	pointer-events: none;
}

/* Badge parked on top of the image. */
.tb-media__badge {
	position: absolute;
	top: var(--tb-space-xs);
	left: var(--tb-space-xs);
	z-index: var(--tb-z-base);
}

/* Duration chip for video thumbnails. */
.tb-media__duration {
	position: absolute;
	right: var(--tb-space-xs);
	bottom: var(--tb-space-xs);
	padding: 0.125rem var(--tb-space-xxs);
	background: rgba(17, 20, 24, 0.85);
	color: var(--tb-ink-inverse);
	font-size: var(--tb-caption-size);
	font-variant-numeric: tabular-nums;
}

/* ===================================================================
 * 6. STORY CARDS
 * Three shapes, one hover contract: image scales, headline turns navy,
 * nothing moves. All share the .tb-card base.
 * ================================================================= */
.tb-card {
	display: flex;
	flex-direction: column;
	min-width: 0;
	background: transparent;   /* the white canvas is the card body */
	border-radius: var(--tb-radius);
}

/* Shared hover contract */
.tb-card:hover .tb-media img { transform: scale(var(--tb-media-hover-scale)); }
.tb-card:hover .tb-card__title > a,
.tb-card:hover .tb-card__title { color: var(--tb-secondary); }

.tb-card__body {
	display: flex;
	flex-direction: column;
	gap: var(--tb-space-xxs);
	padding-top: var(--tb-space-sm);
	min-width: 0;
}

.tb-card__title {
	font-family: var(--tb-font-headline);
	font-size: var(--tb-headline-sm-size);
	line-height: var(--tb-headline-sm-line);
	font-weight: var(--tb-headline-sm-weight);
	color: var(--tb-ink);
	transition: color var(--tb-duration-fast) var(--tb-ease);
}

.tb-card__excerpt {
	font-size: var(--tb-body-sm-size);
	line-height: var(--tb-body-sm-line);
	color: var(--tb-ink-muted);
}

.tb-card__meta {
	margin-top: var(--tb-space-xxs);
	font-size: var(--tb-timestamp-size);
	line-height: var(--tb-timestamp-line);
	color: var(--tb-ink-subtle);
}

/* --- 6a. LEAD CARD — the 8-column anchor ------------------------- */
.tb-card--lead .tb-media { aspect-ratio: var(--tb-ratio-hero); }
.tb-card--lead:hover .tb-media img { transform: scale(var(--tb-media-hover-scale-lead)); }

.tb-card--lead .tb-card__title {
	font-size: var(--tb-headline-lg-size);
	line-height: var(--tb-headline-lg-line);
	font-weight: var(--tb-headline-lg-weight);
	letter-spacing: var(--tb-headline-lg-track);
}

.tb-card--lead .tb-card__excerpt {
	font-size: var(--tb-body-md-size);
	line-height: var(--tb-body-md-line);
	margin-top: var(--tb-space-xxs);
}

/* Hero variant — headline sits over the photograph. */
.tb-card--overlay { position: relative; }
.tb-card--overlay .tb-media { aspect-ratio: var(--tb-ratio-hero); }
.tb-card--overlay .tb-card__body {
	position: absolute;
	inset-inline: 0;
	bottom: 0;
	padding: var(--tb-space-lg);
	color: var(--tb-ink-inverse);
}
.tb-card--overlay .tb-card__title { color: var(--tb-ink-inverse); }
.tb-card--overlay:hover .tb-card__title { color: var(--tb-ink-inverse); }
.tb-card--overlay .tb-card__excerpt,
.tb-card--overlay .tb-card__meta { color: var(--tb-ink-inverse-muted); }

/* --- 6b. ROW CARD — compact horizontal list item ----------------- */
.tb-card--row {
	flex-direction: row;
	gap: var(--tb-space-sm);
	align-items: flex-start;
}
.tb-card--row .tb-media {
	flex-shrink: 0;
	width: 8rem;             /* 128px */
	aspect-ratio: var(--tb-ratio-card);
}
.tb-card--row .tb-card__body {
	padding-top: 0;
	justify-content: space-between;
	flex: 1;
}
.tb-card--row .tb-card__title {
	font-size: var(--tb-body-md-size);
	line-height: 1.3;
	font-weight: 600;
}

@media (min-width: 640px) {
	.tb-card--row .tb-media { width: 9rem; }
	.tb-card--row .tb-card__title {
		font-size: var(--tb-headline-sm-size);
		line-height: var(--tb-headline-sm-line);
	}
}

/* Thumbnail on the right instead — for sidebar lists. */
.tb-card--row-reverse { flex-direction: row-reverse; }

/* --- 6c. TEXT ROW — headline only, no image ---------------------- */
.tb-card--text .tb-card__body { padding-top: 0; }
.tb-card--text .tb-card__title {
	font-size: var(--tb-body-md-size);
	line-height: 1.35;
	font-weight: 600;
}

/* --- 6d. NUMBERED ROW — trending / most-read lists --------------- */
.tb-card--numbered {
	flex-direction: row;
	gap: var(--tb-space-sm);
	align-items: baseline;
}
.tb-card--numbered .tb-card__rank {
	flex-shrink: 0;
	width: 1.5rem;
	font-family: var(--tb-font-headline);
	font-size: var(--tb-headline-md-size);
	font-weight: 700;
	color: var(--tb-primary);
	font-variant-numeric: tabular-nums;
	line-height: 1;
}

/* --- 6e. LISTS — hairline-separated stacks ----------------------- */
.tb-list { display: flex; flex-direction: column; }
.tb-list > * { padding-block: var(--tb-space-sm); border-bottom: var(--tb-rule); }
.tb-list > *:first-child { padding-top: 0; }
.tb-list > *:last-child { padding-bottom: 0; border-bottom: none; }

/* ===================================================================
 * 7. BREAKING / TICKER BANNER  —  .tb-ticker
 * Solid red strip, white uppercase type, pulsing pip.
 * ================================================================= */
.tb-ticker {
	display: flex;
	align-items: center;
	gap: var(--tb-space-sm);
	min-height: 2rem;
}

.tb-ticker__tag {
	display: inline-flex;
	align-items: center;
	gap: var(--tb-space-xxs);
	flex-shrink: 0;
	padding: 0.125rem var(--tb-space-xs);
	background: var(--tb-primary);
	color: var(--tb-on-primary);
	font-size: var(--tb-label-size);
	line-height: var(--tb-label-line);
	font-weight: var(--tb-label-weight);
	letter-spacing: var(--tb-label-track);
	text-transform: uppercase;
}

/* --- The moving part -----------------------------------------------
 * A viewport that clips, a track that translates. The track holds the
 * headlines twice; moving it by exactly -50% lands the copy where the
 * original began, so the loop is seamless rather than snapping back.
 *
 * Duration is set per-instance by tb-ui.js from the measured track
 * width, so the speed stays constant whether there are three headlines
 * or twelve.
 * ------------------------------------------------------------------ */
.tb-ticker__viewport {
	flex: 1;
	min-width: 0;
	overflow: hidden;
	/* Fade the leading and trailing edges so headlines enter and leave
	   instead of being guillotined by the container edge. */
	-webkit-mask-image: linear-gradient(90deg, transparent, #000 2rem, #000 calc(100% - 2rem), transparent);
	        mask-image: linear-gradient(90deg, transparent, #000 2rem, #000 calc(100% - 2rem), transparent);
}

.tb-ticker__track {
	display: flex;
	width: max-content;
	animation: tb-ticker-scroll var(--tb-ticker-duration, 40s) linear infinite;
}

.tb-ticker__group {
	display: flex;
	align-items: center;
	gap: var(--tb-space-lg);
	padding-right: var(--tb-space-lg);
	flex-shrink: 0;
}

@keyframes tb-ticker-scroll {
	from { transform: translateX(0); }
	to   { transform: translateX(-50%); }
}

/* Stop while someone is reading or tabbing through, and when they've
   asked it to stop. */
.tb-ticker:hover .tb-ticker__track,
.tb-ticker:focus-within .tb-ticker__track,
.tb-ticker.is-paused .tb-ticker__track {
	animation-play-state: paused;
}

.tb-ticker__item {
	flex-shrink: 0;
	white-space: nowrap;
	font-size: var(--tb-body-sm-size);
	color: var(--tb-ink);
	transition: color var(--tb-duration-fast) var(--tb-ease);
}
.tb-ticker__item:hover,
.tb-ticker__item:focus-visible { color: var(--tb-primary); }

/* Separator between headlines — a dot the item carries with it, so the
   spacing stays even as the track loops. */
.tb-ticker__item + .tb-ticker__item::before {
	content: "";
	display: inline-block;
	width: 4px;
	height: 4px;
	margin-right: var(--tb-space-lg);
	border-radius: var(--tb-radius-circle);
	background: var(--tb-border-strong);
	vertical-align: middle;
}

/* --- Pause control -------------------------------------------------- */
.tb-ticker__toggle {
	flex-shrink: 0;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 1.5rem;
	height: 1.5rem;
	margin-left: var(--tb-space-xs);
	color: var(--tb-ink-subtle);
	transition: color var(--tb-duration-fast) var(--tb-ease);
}
.tb-ticker__toggle:hover { color: var(--tb-primary); }

/* Two bars for pause; a triangle for play. Drawn in CSS so the control
   costs nothing extra to load. */
.tb-ticker__toggle-icon {
	width: 8px;
	height: 9px;
	border-left: 3px solid currentColor;
	border-right: 3px solid currentColor;
}
.tb-ticker.is-paused .tb-ticker__toggle-icon {
	width: 0;
	height: 0;
	border-left: 8px solid currentColor;
	border-right: 0;
	border-top: 5px solid transparent;
	border-bottom: 5px solid transparent;
}

/* Reduced motion: no marquee at all. The track becomes a normal
   horizontally scrollable strip, and the duplicate is hidden so the
   headlines aren't listed twice. */
@media (prefers-reduced-motion: reduce) {
	.tb-ticker__viewport {
		overflow-x: auto;
		scrollbar-width: none;
		-webkit-mask-image: none;
		        mask-image: none;
	}
	.tb-ticker__viewport::-webkit-scrollbar { display: none; }
	.tb-ticker__track { animation: none; }
	.tb-ticker__group[aria-hidden="true"] { display: none; }
	.tb-ticker__toggle { display: none; }
}

/* Full-bleed breaking bar — the loudest thing on the page. */
.tb-breaking {
	background: var(--tb-primary);
	color: var(--tb-on-primary);
}
.tb-breaking .tb-ticker__tag {
	background: var(--tb-on-primary);
	color: var(--tb-primary);
}
.tb-breaking .tb-ticker__item { color: var(--tb-on-primary); font-weight: 500; }
.tb-breaking .tb-ticker__item:hover { color: var(--tb-on-primary); text-decoration: underline; }

/* ===================================================================
 * 8. BUTTONS  —  .tb-btn
 * Squared, unshadowed, two weights.
 * ================================================================= */
.tb-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--tb-space-xxs);
	padding: var(--tb-space-xs) var(--tb-space-sm);
	border-radius: var(--tb-radius);
	border: 1px solid transparent;
	font-family: var(--tb-font-body);
	font-size: var(--tb-body-sm-size);
	font-weight: 700;
	line-height: 1.25rem;
	text-align: center;
	cursor: pointer;
	transition: background-color var(--tb-duration-fast) var(--tb-ease),
	            color var(--tb-duration-fast) var(--tb-ease),
	            border-color var(--tb-duration-fast) var(--tb-ease);
}

.tb-btn--primary {
	background: var(--tb-ink);
	color: var(--tb-ink-inverse);
}
.tb-btn--primary:hover { background: #000; }

.tb-btn--red {
	background: var(--tb-primary);
	color: var(--tb-on-primary);
}
.tb-btn--red:hover { background: var(--tb-primary-dark); }

.tb-btn--navy {
	background: var(--tb-secondary);
	color: var(--tb-on-secondary);
}
.tb-btn--navy:hover { background: var(--tb-secondary-dark); }

/* Secondary / Load More — outlined, centered. */
.tb-btn--outline {
	background: var(--tb-surface);
	color: var(--tb-ink);
	border-color: var(--tb-border-strong);
}
.tb-btn--outline:hover { background: var(--tb-surface-sunken); }

.tb-btn--ghost { background: transparent; color: var(--tb-ink); }
.tb-btn--ghost:hover { background: var(--tb-surface-muted); }

.tb-btn--lg { padding: var(--tb-space-sm) var(--tb-space-lg); font-size: var(--tb-body-md-size); }
.tb-btn--sm { padding: var(--tb-space-xxs) var(--tb-space-xs); font-size: var(--tb-caption-size); }
.tb-btn--block { display: flex; width: 100%; }

.tb-btn:disabled,
.tb-btn[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; }

.tb-btn svg { width: 1em; height: 1em; }

/* ===================================================================
 * 9. FORM CONTROLS  —  .tb-input / .tb-search
 * 1px perimeter, sharp corners, navy focus with no outer glow.
 * ================================================================= */
.tb-input,
.tb-textarea,
.tb-select {
	width: 100%;
	padding: var(--tb-space-xs) var(--tb-space-sm);
	background: var(--tb-surface);
	color: var(--tb-ink);
	border: 1px solid var(--tb-border-strong);
	border-radius: var(--tb-radius);
	font-size: var(--tb-body-md-size);
	line-height: 1.5rem;
	transition: border-color var(--tb-duration-fast) var(--tb-ease);
}
.tb-input::placeholder,
.tb-textarea::placeholder { color: var(--tb-ink-faint); }

.tb-input:focus,
.tb-textarea:focus,
.tb-select:focus {
	outline: none;
	border-color: var(--tb-secondary);
}

.tb-textarea { min-height: 8rem; resize: vertical; }

/* Search field with an inline glass icon. */
.tb-search { position: relative; display: flex; align-items: center; }
.tb-search .tb-input { padding-right: 2rem; }
.tb-search__icon {
	position: absolute;
	right: var(--tb-space-xs);
	width: 16px;
	height: 16px;
	color: var(--tb-ink-subtle);
	pointer-events: none;
}
.tb-search--compact .tb-input {
	padding-block: 0.25rem;
	font-size: var(--tb-body-sm-size);
	background: var(--tb-surface-sunken);
	border-color: var(--tb-border);
}

.tb-field { display: flex; flex-direction: column; gap: var(--tb-space-xxs); }
.tb-field__label {
	font-size: var(--tb-body-sm-size);
	font-weight: 600;
	color: var(--tb-ink);
}
.tb-field__hint { font-size: var(--tb-caption-size); color: var(--tb-ink-subtle); }
.tb-field__error { font-size: var(--tb-caption-size); color: var(--tb-error); }

/* ===================================================================
 * 10. TAGS  —  .tb-tag
 * Outlined pills for topic lists under an article.
 * ================================================================= */
.tb-tag {
	display: inline-flex;
	align-items: center;
	padding: var(--tb-space-xxs) var(--tb-space-xs);
	border: var(--tb-rule-strong);
	border-radius: var(--tb-radius);
	font-size: var(--tb-body-sm-size);
	color: var(--tb-ink-muted);
	transition: border-color var(--tb-duration-fast) var(--tb-ease),
	            color var(--tb-duration-fast) var(--tb-ease);
}
.tb-tag:hover { border-color: var(--tb-secondary); color: var(--tb-secondary); }

/* ===================================================================
 * 11. PAGINATION  —  .tb-pagination
 * ================================================================= */
.tb-pagination {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	align-items: center;
	gap: var(--tb-space-xxs);
	margin-top: var(--tb-space-xl);
	padding-top: var(--tb-space-lg);
	border-top: var(--tb-rule);
}
.tb-pagination .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 2.25rem;
	height: 2.25rem;
	padding-inline: var(--tb-space-xs);
	border: var(--tb-rule-strong);
	font-size: var(--tb-body-sm-size);
	font-weight: 600;
	color: var(--tb-ink);
	transition: background-color var(--tb-duration-fast) var(--tb-ease),
	            color var(--tb-duration-fast) var(--tb-ease);
}
.tb-pagination .page-numbers:hover { background: var(--tb-surface-sunken); }
.tb-pagination .page-numbers.current {
	background: var(--tb-ink);
	border-color: var(--tb-ink);
	color: var(--tb-ink-inverse);
}
.tb-pagination .page-numbers.dots { border-color: transparent; }

/* ===================================================================
 * 12. NOTICES  —  .tb-notice
 * ================================================================= */
.tb-notice {
	padding: var(--tb-space-sm) var(--tb-space-md);
	border-left: 3px solid var(--tb-accent);
	background: var(--tb-surface-sunken);
	font-size: var(--tb-body-md-size);
}
.tb-notice--error   { border-left-color: var(--tb-error);   background: var(--tb-error-tint); }
.tb-notice--success { border-left-color: var(--tb-success); background: var(--tb-success-tint); }
.tb-notice--warning { border-left-color: var(--tb-warning); background: var(--tb-warning-tint); }

/* ===================================================================
 * 13. EMPTY STATE  —  .tb-empty
 * ================================================================= */
.tb-empty {
	padding: var(--tb-space-2xl) var(--tb-space-md);
	text-align: center;
	border: var(--tb-rule);
	background: var(--tb-surface-sunken);
}
.tb-empty__title {
	font-family: var(--tb-font-headline);
	font-size: var(--tb-headline-md-size);
	font-weight: 600;
	margin-bottom: var(--tb-space-xs);
}
.tb-empty__text { color: var(--tb-ink-muted); font-size: var(--tb-body-md-size); }

/* ===================================================================
 * 14. PAGE LAYOUT & SIDEBAR MODULES
 * These live here rather than in tb-homepage.css because articles,
 * archives and search results all use the same two-column shell and
 * the same sidebar modules. Keeping them in the homepage sheet meant
 * a single post rendered its sidebar with no layout at all.
 * ================================================================= */
.tb-layout {
	display: grid;
	gap: var(--tb-space-xl);
	grid-template-columns: 1fr;
}
@media (min-width: 1024px) {
	.tb-layout { grid-template-columns: minmax(0, 1fr) 20rem; gap: var(--tb-space-2xl); }
}

.tb-sidebar {
	display: flex;
	flex-direction: column;
	gap: var(--tb-space-xl);
	min-width: 0;
}
@media (min-width: 1024px) {
	.tb-sidebar--sticky {
		position: sticky;
		top: calc(var(--tb-header-sticky, var(--tb-header-height)) + var(--tb-space-md));
		align-self: start;
	}
}

.tb-module { display: flex; flex-direction: column; }

.tb-module--boxed {
	padding: var(--tb-space-md);
	background: var(--tb-surface-sunken);
	border: var(--tb-rule);
}

/* Newsletter signup */
.tb-newsletter { display: flex; flex-direction: column; gap: var(--tb-space-sm); }
.tb-newsletter__title {
	font-family: var(--tb-font-headline);
	font-size: var(--tb-headline-md-size);
	line-height: var(--tb-headline-md-line);
	font-weight: 600;
}
.tb-newsletter__text { font-size: var(--tb-body-sm-size); color: var(--tb-ink-muted); }

/* Weather panel */
.tb-weather-list { display: flex; flex-direction: column; }
.tb-weather-row {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--tb-space-sm);
	padding-block: var(--tb-space-xs);
	border-bottom: var(--tb-rule);
	font-size: var(--tb-body-sm-size);
}
.tb-weather-row:last-child { border-bottom: none; }
.tb-weather-row__town { color: var(--tb-ink); font-weight: 500; }
.tb-weather-row__temp { font-variant-numeric: tabular-nums; color: var(--tb-ink-muted); }

/* Ad slot — reserved space, so no layout shift when a creative loads. */
.tb-adslot {
	display: flex;
	align-items: center;
	justify-content: center;
	background: var(--tb-surface-sunken);
	border: var(--tb-rule);
	color: var(--tb-ink-faint);
	font-size: var(--tb-caption-size);
	text-transform: uppercase;
	letter-spacing: var(--tb-label-track);
	min-height: 250px;
}
.tb-adslot--leaderboard { min-height: 90px; }
.tb-adslot--billboard { min-height: 250px; }

/* --- tb-header-footer --- */
/**
 * Totoong Balita — Masthead & Footer
 * The fixed three-tier header (utility bar / wordmark / nav), the mobile
 * drawer, and the dark footer.
 */

/* ===================================================================
 * MASTHEAD
 * Three stacked rows inside one fixed band:
 *   1. utility  — date, edition, search, account
 *   2. brand    — wordmark and tagline
 *   3. nav      — primary sections + weather chip
 * ================================================================= */
.tb-header {
	position: fixed;
	top: 0;
	left: 0;
	width: 100%;
	z-index: var(--tb-z-header);
	background: var(--tb-surface);
	border-bottom: var(--tb-rule);
}

.tb-header__inner {
	display: flex;
	flex-direction: column;
}

/* --- Scroll behaviour (headroom) ----------------------------------
   Scrolling down past the masthead slides the whole band out of view.
   Scrolling up brings it straight back, but condensed: the utility
   strip and the ticker stay collapsed and the wordmark row shrinks, so
   the returning bar costs ~92px instead of ~176px. Reaching the top of
   the page restores the full masthead.

   The collapse uses grid 1fr -> 0fr rather than animating a height,
   because the ticker row is content-sized and has no height to animate.

   IMPORTANT: --tb-header-height must NOT track the live header. It
   reserves main's top padding; if it shrank as the header condensed,
   the page would lurch upward, which changes scrollY, which re-fires
   the scroll handler — a feedback loop. tb-ui.js measures both heights
   once, with transitions suppressed, and publishes them as constants. */
.tb-header {
	transition: transform var(--tb-duration-fast) var(--tb-ease);
	will-change: transform;
}

.tb-header.is-hidden { transform: translateY(-100%); }

.tb-header__collapse {
	display: grid;
	grid-template-rows: 1fr;
	transition: grid-template-rows var(--tb-duration-fast) var(--tb-ease);
}
.tb-header__collapse-inner {
	overflow: hidden;
	min-height: 0;
}

.tb-header.is-condensed .tb-header__collapse { grid-template-rows: 0fr; }

/* Clipped content stays focusable, so a keyboard user could tab into a
   search field they cannot see. visibility removes it from the tab
   order — delayed on the way out so it does not blink away before the
   row has finished collapsing, immediate on the way back in. */
.tb-header.is-condensed .tb-header__collapse-inner {
	visibility: hidden;
	transition: visibility 0s linear var(--tb-duration-fast);
}

/* Nothing to animate off-screen. */
.tb-header.is-condensed .tb-ticker__track { animation-play-state: paused; }

/* The wordmark row shrinks rather than disappearing — the masthead
   should still say whose site this is. */
.tb-header .tb-header__brand {
	transition: height var(--tb-duration-fast) var(--tb-ease);
}
.tb-header .tb-wordmark {
	transition: font-size var(--tb-duration-fast) var(--tb-ease);
}
.tb-header.is-condensed .tb-header__brand { height: 3rem; }
.tb-header.is-condensed .tb-wordmark { font-size: var(--tb-headline-lg-size); }
.tb-header.is-condensed .tb-wordmark__suffix { font-size: var(--tb-body-size); }

/* Measurement pass: tb-ui.js toggles the real state classes to read
   both heights and must not see interpolated values. */
.tb-header.is-measuring,
.tb-header.is-measuring * { transition: none !important; }

/* Reduced motion needs no rules here: tb-tokens.css already sets
   --tb-duration-fast to 0ms under that query, so every transition above
   — including the visibility delay — collapses to an instant state
   change. The header still condenses and hides; that is screen space,
   not decoration. It just stops sliding. */

/* --- Row 1: utility ---------------------------------------------- */
.tb-header__utility {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--tb-space-md);
	height: 2.25rem;
	border-bottom: var(--tb-rule);
}

.tb-header__date {
	font-size: var(--tb-timestamp-size);
	color: var(--tb-ink-subtle);
	text-transform: uppercase;
	letter-spacing: 0.04em;
	white-space: nowrap;
}

.tb-header__divider {
	width: 1px;
	height: 0.75rem;
	background: var(--tb-border);
	flex-shrink: 0;
}

.tb-header__edition {
	font-size: var(--tb-label-size);
	font-weight: var(--tb-label-weight);
	letter-spacing: var(--tb-label-track);
	text-transform: uppercase;
	color: var(--tb-tertiary);
	white-space: nowrap;
}

.tb-header__utility-actions {
	display: flex;
	align-items: center;
	gap: var(--tb-space-sm);
	flex-shrink: 0;
}

.tb-header__search { width: 10rem; min-width: 0; }
@media (min-width: 640px) { .tb-header__search { width: 14rem; } }

/* --- Utility strip: shedding detail instead of wrapping ------------
   The strip is a fixed-height 2.25rem bar. `.tb-cluster` wraps by
   default, so at mid widths the edition dropped to a second line, the
   cluster grew to 62px, and — being vertically centred in a 36px bar —
   bled out of it at BOTH ends: the date clipped above the header, the
   edition spilling down over the masthead. Measured at 660px.

   So this cluster never wraps. It sheds detail instead, least
   load-bearing first, and the strip stays exactly one line tall. */
.tb-header__meta {
	flex-wrap: nowrap;
	min-width: 0;
}

.tb-header__date-short { display: none; }

/* 1. The word "Edisyon:" goes first — the region names say it alone. */
@media (max-width: 1023px) {
	.tb-header__edition-label { display: none; }
}

/* 2. Then the weekday and the spelled-out month: "25 Set 2026". */
@media (max-width: 879px) {
	.tb-header__date-long  { display: none; }
	.tb-header__date-short { display: inline; }
}

/* 3. Then the edition itself. Row 2's standfirst and the footer both
      still name the region, so nothing is actually lost here. */
@media (max-width: 559px) {
	.tb-header__divider,
	.tb-header__edition { display: none; }
}

/* 4. Finally the search field, which collapses to its own icon below
      768px (see "Mobile search"). The date stays: with the field out
      of the flow there is room for it again, and a strip holding one
      icon and nothing else is a wasted rule. */

/* --- Mobile search: a glass that expands over the date -------------
   A permanent full-width field was taking the whole strip on a phone
   and pushing the masthead down the page. Below 768px it becomes a
   magnifying glass at the right-hand end, and opens leftward across
   the row, over the date.

   Taken out of the flow rather than grown from zero width: animating
   the form's width squeezes the input inside it, so the placeholder
   compresses as it opens. Laid out at full width and revealed with
   clip-path, the text never moves — it is uncovered, right to left.

   Open state is a class on the header, not the `hidden` attribute:
   `hidden` would have to fight a media query over who gets to say
   `display`, and that argument has no good ending. */
.tb-header__searchbtn { display: none; }

@media (max-width: 767px) {
	.tb-header__utility { position: relative; }

	.tb-header__searchbtn {
		display: inline-flex;
		align-items: center;
		justify-content: center;
		width: 2rem;
		height: 2rem;
		flex-shrink: 0;
		margin-right: calc(var(--tb-space-xxs) * -1);   /* optical edge */
		padding: 0;
		border: 0;
		background: none;
		color: var(--tb-ink-subtle);
		cursor: pointer;
		transition: color var(--tb-duration-fast) var(--tb-ease);
	}
	.tb-header__searchbtn:hover,
	.tb-header.is-searching .tb-header__searchbtn { color: var(--tb-ink); }
	.tb-header__searchbtn svg { width: 18px; height: 18px; }

	.tb-header__search {
		position: absolute;
		top: 50%;
		left: 0;
		right: calc(2rem + var(--tb-space-xs));
		width: auto;
		transform: translateY(-50%);
		opacity: 0;
		visibility: hidden;
		clip-path: inset(0 0 0 100%);
		/* visibility is delayed out so the reveal can finish playing
		   backwards before the field leaves the tab order. */
		transition: opacity var(--tb-duration-fast) var(--tb-ease),
		            clip-path var(--tb-duration-fast) var(--tb-ease),
		            visibility 0s linear var(--tb-duration-fast);
	}

	.tb-header.is-searching .tb-header__search {
		opacity: 1;
		visibility: visible;
		clip-path: inset(0 0 0 0);
		transition-delay: 0s;
	}

	/* The field carries its own inline glass, which sat right beside
	   the button that opened it — two identical icons an inch apart,
	   one of them inert. The button is the glass here, so the field's
	   own is dropped and the padding it reserved comes back. */
	.tb-header__search .tb-search__icon { display: none; }
	.tb-header__search .tb-input { padding-right: var(--tb-space-xs); }

	/* The date sits underneath. visibility rather than display so the
	   strip keeps its height and nothing jumps. */
	.tb-header.is-searching .tb-header__meta { visibility: hidden; }
}

.tb-header__account {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 2rem;
	height: 2rem;
	flex-shrink: 0;
	border-radius: var(--tb-radius-circle);   /* avatar — sanctioned circle */
	background: var(--tb-primary);
	color: var(--tb-on-primary);
	transition: background-color var(--tb-duration-fast) var(--tb-ease);
}
.tb-header__account:hover { background: var(--tb-primary-dark); }

/* Latest draw, beside the weather. Lives here rather than in tb-lotto.css
   because the masthead renders on every page and that sheet does not. */
.tb-header__lotto {
	display: inline-flex;
	align-items: center;
	gap: var(--tb-space-xxs);
	font-size: var(--tb-caption-size);
	color: var(--tb-ink-subtle);
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}
.tb-header__lotto:hover { color: var(--tb-primary); }
.tb-header__lotto svg { width: 14px; height: 14px; flex-shrink: 0; }

/* The navrow's right-hand tray. Two chips now, so they need a container
   of their own rather than each shrinking against the nav independently. */
.tb-header__chips {
	display: flex;
	align-items: center;
	gap: var(--tb-space-md);
	flex-shrink: 0;
}
.tb-header__account svg { width: 18px; height: 18px; }

/* --- Row 2: brand ------------------------------------------------- */
.tb-header__brand {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--tb-space-md);
	height: 4rem;
}

/* Room to breathe around the lockup in the full desktop header.
 *
 * The row was 4rem (64px) while the brandmark — 48px wordmark plus the
 * strapline beneath it — measures 67px. It was not merely tight, it
 * overflowed by 3px and sat hard against the rule above and below.
 *
 * Expressed as a taller row rather than padding on purpose: tb-ui.js
 * animates this element between its full and condensed heights, and
 * `height: auto` with padding cannot be transitioned — the masthead
 * would snap instead of collapsing. 5.5rem leaves ~10px of clearance
 * top and bottom and keeps the animation intact.
 *
 * Mobile keeps 4rem: the wordmark steps down to 30px there, so the
 * lockup is around 46px and already clears comfortably. */
@media (min-width: 768px) {
	.tb-header:not(.is-condensed) .tb-header__brand { height: 5.5rem; }
}

.tb-header__lockup {
	display: flex;
	align-items: baseline;
	gap: var(--tb-space-sm);
	min-width: 0;
}

.tb-wordmark {
	display: inline-flex;
	align-items: baseline;
	gap: var(--tb-space-xxs);
	font-family: var(--tb-font-headline);
	font-size: var(--tb-display-hero-size);
	line-height: 1;
	font-weight: 700;
	letter-spacing: var(--tb-display-hero-track);
	color: var(--tb-primary);
	white-space: nowrap;
}
.tb-wordmark__suffix {
	font-size: var(--tb-headline-lg-size);
	font-weight: 400;
	font-style: italic;
	letter-spacing: normal;
	color: var(--tb-ink);
}
.tb-wordmark img { max-height: 3rem; width: auto; }

.tb-header__tagline {
	font-size: var(--tb-caption-size);
	color: var(--tb-ink-subtle);
	text-transform: uppercase;
	letter-spacing: 0.04em;
	padding-left: var(--tb-space-xs);
}

.tb-header__standfirst {
	display: flex;
	flex-direction: column;
	text-align: right;
	flex-shrink: 0;
}
.tb-header__standfirst-lead {
	/* The slogan is set in the masthead's serif, not the interface
	   sans. It belongs to the nameplate beside it rather than to the
	   navigation around it, and Newsreader 700 is already loaded for
	   headlines, so this costs no extra font request. */
	font-family: var(--tb-font-headline);
	/* Twice the label size: this is the masthead's slogan now, not a
	   descriptive line, so it carries the weight rather than sitting as
	   a caption beside the wordmark. */
	font-size: calc(var(--tb-label-size) * 2);
	font-weight: var(--tb-label-weight);
	/* Tracking set for small uppercase labels opens gaps at this size. */
	letter-spacing: 0;
	/* Rendered as written. At twice the size the uppercase transform this
	   rule used to carry would shout, and the line has its own
	   exclamation mark to do that job. */
	text-transform: none;
	line-height: 1.1;
	color: var(--tb-primary);
}
.tb-header__standfirst-sub {
	font-size: var(--tb-caption-size);
	color: var(--tb-ink-subtle);
}

/* --- Row 3: primary navigation ------------------------------------ */
.tb-header__navrow {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--tb-space-md);
	height: 2.75rem;
	border-top: var(--tb-rule);
}

.tb-nav {
	display: flex;
	align-items: center;
	gap: var(--tb-space-md);
	height: 100%;
	overflow-x: auto;
	white-space: nowrap;
	scrollbar-width: none;
}
.tb-nav::-webkit-scrollbar { display: none; }

@media (min-width: 640px) { .tb-nav { gap: var(--tb-space-lg); } }

.tb-nav__link {
	display: flex;
	align-items: center;
	height: 100%;
	font-size: var(--tb-label-size);
	line-height: var(--tb-label-line);
	font-weight: var(--tb-label-weight);
	letter-spacing: var(--tb-label-track);
	text-transform: uppercase;
	color: var(--tb-ink-muted);
	border-bottom: 2px solid transparent;
	transition: color var(--tb-duration-fast) var(--tb-ease),
	            border-color var(--tb-duration-fast) var(--tb-ease);
}
.tb-nav__link:hover { color: var(--tb-ink); }

/* Active section — red underline, no layout shift (border is always there) */
.tb-nav__link.is-active,
.tb-nav__item.current-menu-item > .tb-nav__link {
	color: var(--tb-primary);
	border-bottom-color: var(--tb-primary);
}

.tb-header__weather {
	display: inline-flex;
	align-items: center;
	gap: var(--tb-space-xxs);
	flex-shrink: 0;
	padding-left: var(--tb-space-md);
	font-size: var(--tb-caption-size);
	color: var(--tb-ink-subtle);
}
.tb-header__weather svg { width: 14px; height: 14px; color: var(--tb-tertiary); }

/* --- Weather picker ------------------------------------------------
   One town, and the reader chooses which. The chip used to show the
   first two in the list, which was two cities neither of them was
   necessarily near. Every town's reading is already in the page, so
   switching costs no request. */
.tb-wxpick { position: relative; }

.tb-wxpick__btn {
	display: inline-flex;
	align-items: center;
	gap: var(--tb-space-xxs);
	padding: var(--tb-space-xxs) 0;
	border: 0;
	background: none;
	font: inherit;
	color: inherit;
	cursor: pointer;
	transition: color var(--tb-duration-fast) var(--tb-ease);
}
.tb-wxpick__btn:hover { color: var(--tb-ink); }
.tb-wxpick__caret {
	color: var(--tb-ink-faint) !important;   /* beats .tb-header__weather svg */
	transition: transform var(--tb-duration-fast) var(--tb-ease);
}
.tb-wxpick__btn[aria-expanded="true"] .tb-wxpick__caret { transform: rotate(180deg); }

.tb-wxpick__menu {
	position: absolute;
	top: calc(100% + var(--tb-space-xxs));
	right: 0;
	/* Inside the header's own stacking context, so it only has to clear
	   its siblings — the scale has no dropdown step and this does not
	   warrant inventing one. */
	z-index: var(--tb-z-sticky);
	width: 15rem;
	max-height: 60vh;
	overflow-y: auto;
	background: var(--tb-surface);
	border: var(--tb-rule-strong);
	/* No shadow tokens in this system — the strong rule is the lift. */
}

.tb-wxpick__list { list-style: none; margin: 0; padding: 0; }

.tb-wxpick__opt {
	display: flex;
	align-items: baseline;
	gap: var(--tb-space-xs);
	width: 100%;
	padding: var(--tb-space-xs) var(--tb-space-sm);
	border: 0;
	background: none;
	font-family: var(--tb-font-body);
	font-size: var(--tb-body-sm-size);
	text-align: left;
	color: var(--tb-ink);
	cursor: pointer;
	transition: background-color var(--tb-duration-fast) var(--tb-ease);
}
.tb-wxpick__opt:hover { background: var(--tb-surface-sunken); }
.tb-wxpick__opt.is-current { font-weight: 700; }

.tb-wxpick__town { flex-shrink: 0; }
.tb-wxpick__prov {
	flex: 1;
	min-width: 0;
	font-size: var(--tb-caption-size);
	color: var(--tb-ink-faint);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.tb-wxpick__temp {
	flex-shrink: 0;
	font-variant-numeric: tabular-nums;
	color: var(--tb-ink-muted);
}

.tb-wxpick__opt--locate {
	align-items: center;
	gap: var(--tb-space-xs);
	border-bottom: var(--tb-rule);
	color: var(--tb-secondary);
	font-weight: 600;
}
.tb-wxpick__opt--locate svg { color: currentColor !important; }
.tb-wxpick__opt--locate[disabled] { opacity: 0.6; cursor: default; }

/* Says which town the coordinates landed on, or why they did not. The
   site covers nine towns; a reader outside them gets the nearest one
   named rather than presented as theirs. */
.tb-wxpick__note {
	margin: 0;
	padding: var(--tb-space-xs) var(--tb-space-sm);
	border-bottom: var(--tb-rule);
	background: var(--tb-surface-sunken);
	font-size: var(--tb-caption-size);
	color: var(--tb-ink-muted);
}

/* --- Row 4: regional ticker --------------------------------------- */
.tb-header__ticker {
	background: var(--tb-surface-sunken);
	border-top: var(--tb-rule);
}

/* --- Mobile menu toggle -------------------------------------------- */
.tb-header__burger {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 2.25rem;
	height: 2.25rem;
	margin-left: calc(var(--tb-space-xs) * -1);
	color: var(--tb-ink);
	flex-shrink: 0;
}
.tb-header__burger svg { width: 24px; height: 24px; }

/* The drawer duplicates the section bar exactly, so only one of them
   shows at a time: drawer on phones, the scrolling bar from 768 up. */
@media (min-width: 768px) { .tb-header__burger { display: none; } }
@media (max-width: 767px) { .tb-header__navrow { display: none; } }

/* ===================================================================
 * MOBILE DRAWER
 * ================================================================= */
.tb-drawer {
	position: fixed;
	inset: 0;
	z-index: var(--tb-z-drawer);
	visibility: hidden;
	pointer-events: none;
}
.tb-drawer.is-open { visibility: visible; pointer-events: auto; }

.tb-drawer__scrim {
	position: absolute;
	inset: 0;
	background: rgba(17, 20, 24, 0.5);
	opacity: 0;
	transition: opacity var(--tb-duration) var(--tb-ease);
}
.tb-drawer.is-open .tb-drawer__scrim { opacity: 1; }

.tb-drawer__panel {
	position: absolute;
	top: 0;
	left: 0;
	width: min(20rem, 85vw);
	height: 100%;
	display: flex;
	flex-direction: column;
	background: var(--tb-surface-inverse);
	color: var(--tb-ink-inverse);
	transform: translateX(-100%);
	transition: transform var(--tb-duration) var(--tb-ease);
	overflow-y: auto;
}
.tb-drawer.is-open .tb-drawer__panel { transform: translateX(0); }

.tb-drawer__head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--tb-space-md);
	padding: var(--tb-space-md);
	border-bottom: var(--tb-rule-inverse);
}
/* The wordmark's "News" suffix inherits --tb-ink, which is invisible on
   the drawer's dark panel. Re-point it, and drop the lockup to headline
   scale so it doesn't dominate the panel head. */
.tb-drawer .tb-wordmark { font-size: var(--tb-headline-lg-size); }
.tb-drawer .tb-wordmark__suffix {
	color: var(--tb-ink-inverse);
	font-size: var(--tb-headline-md-size);
}

.tb-drawer__close {
	display: inline-flex;
	padding: var(--tb-space-xxs);
	color: var(--tb-ink-inverse);
}
.tb-drawer__close svg { width: 24px; height: 24px; }

.tb-drawer__nav { display: flex; flex-direction: column; padding: var(--tb-space-xs) 0; }
.tb-drawer__link {
	padding: var(--tb-space-sm) var(--tb-space-md);
	font-size: var(--tb-subhead-size);
	font-weight: 600;
	color: var(--tb-ink-inverse);
	border-bottom: var(--tb-rule-inverse);
	transition: background-color var(--tb-duration-fast) var(--tb-ease);
}
.tb-drawer__link:hover { background: var(--tb-surface-inverse-alt); }
.tb-drawer__link.is-active { color: var(--tb-primary-tint); border-left: 3px solid var(--tb-primary); }

/* Sign-in, pinned to the foot of the panel.
   The masthead's account icon is hidden below 768px and the utility
   strip has no room for it — by 419px it is one full-width search
   field. It lives here instead, below the sections, because it is the
   least-used thing in the drawer and should read that way.
   margin-top:auto pins it to the bottom on a tall phone; with enough
   sections to fill the panel it simply follows the last link. */
.tb-drawer__foot {
	margin-top: auto;
	padding: var(--tb-space-md);
	border-top: var(--tb-rule-inverse);
}

.tb-drawer__account {
	display: flex;
	align-items: center;
	gap: var(--tb-space-sm);
	font-size: var(--tb-body-sm-size);
	font-weight: 600;
	color: var(--tb-ink-inverse-muted);
	transition: color var(--tb-duration-fast) var(--tb-ease);
}
.tb-drawer__account:hover { color: var(--tb-ink-inverse); }

/* The same red disc as the masthead's account chip, so the two read as
   one control that moved rather than two different things. */
.tb-drawer__account-icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 2rem;
	height: 2rem;
	flex-shrink: 0;
	border-radius: var(--tb-radius-circle);   /* avatar — sanctioned circle */
	background: var(--tb-primary);
	color: var(--tb-on-primary);
	transition: background-color var(--tb-duration-fast) var(--tb-ease);
}
.tb-drawer__account:hover .tb-drawer__account-icon { background: var(--tb-primary-dark); }
.tb-drawer__account-icon svg { width: 18px; height: 18px; }

body.tb-drawer-open { overflow: hidden; }

/* ===================================================================
 * MAIN OFFSET
 * The fixed masthead is measured at runtime; main is padded to match.
 * ================================================================= */
.tb-main {
	padding-top: var(--tb-header-height);
	min-height: 60vh;
}
.tb-main__inner { padding-block: var(--tb-space-lg); }

/* ===================================================================
 * FOOTER
 * ================================================================= */
.tb-footer {
	background: var(--tb-surface-inverse);
	color: var(--tb-ink-inverse);
	margin-top: var(--tb-space-2xl);
}

.tb-footer__top {
	display: grid;
	gap: var(--tb-space-xl);
	padding-block: var(--tb-space-2xl);
	grid-template-columns: 1fr;
}
@media (min-width: 768px) {
	.tb-footer__top { grid-template-columns: 1.4fr 1fr 1fr; }
}
@media (min-width: 1024px) {
	.tb-footer__top { grid-template-columns: 1.6fr 1fr 1fr 1fr; }
}

.tb-footer__brandblock { display: flex; flex-direction: column; gap: var(--tb-space-sm); }
.tb-footer .tb-wordmark { color: var(--tb-ink-inverse); font-size: var(--tb-headline-lg-size); }
.tb-footer .tb-wordmark__suffix { color: var(--tb-ink-inverse-muted); font-size: var(--tb-headline-md-size); }
.tb-footer__blurb {
	font-size: var(--tb-body-sm-size);
	line-height: var(--tb-body-sm-line);
	color: var(--tb-ink-inverse-muted);
	max-width: 32ch;
}

.tb-footer__col-title {
	font-size: var(--tb-label-size);
	font-weight: var(--tb-label-weight);
	letter-spacing: var(--tb-label-track);
	text-transform: uppercase;
	color: var(--tb-ink-inverse);
	padding-bottom: var(--tb-space-xs);
	margin-bottom: var(--tb-space-sm);
	border-bottom: var(--tb-rule-inverse);
}

.tb-footer__list { display: flex; flex-direction: column; gap: var(--tb-space-xs); }
.tb-footer__list a {
	font-size: var(--tb-body-sm-size);
	color: var(--tb-ink-inverse-muted);
	transition: color var(--tb-duration-fast) var(--tb-ease);
}
.tb-footer__list a:hover { color: var(--tb-ink-inverse); }

.tb-footer__social { display: flex; gap: var(--tb-space-xs); margin-top: var(--tb-space-xs); }
.tb-footer__social a {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 2rem;
	height: 2rem;
	border: var(--tb-rule-inverse);
	color: var(--tb-ink-inverse-muted);
	transition: background-color var(--tb-duration-fast) var(--tb-ease),
	            color var(--tb-duration-fast) var(--tb-ease);
}
.tb-footer__social a:hover {
	background: var(--tb-primary);
	border-color: var(--tb-primary);
	color: var(--tb-on-primary);
}
.tb-footer__social svg { width: 16px; height: 16px; }

.tb-footer__bottom {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--tb-space-sm);
	padding-block: var(--tb-space-md);
	border-top: var(--tb-rule-inverse);
	font-size: var(--tb-caption-size);
	color: var(--tb-ink-inverse-muted);
}
.tb-footer__legal { display: flex; flex-wrap: wrap; gap: var(--tb-space-md); }
.tb-footer__legal a:hover { color: var(--tb-ink-inverse); }

/* ===================================================================
 * ADMIN BAR OFFSET
 * The masthead is position:fixed at top:0, and so is WordPress's admin
 * bar — which wins on z-index and covers the top of the header for
 * logged-in users. That hides the breaking banner from exactly the
 * people who need to know it is live.
 * WP uses 32px from 783px up, 46px below that.
 * ================================================================= */
.admin-bar .tb-header { top: 32px; }

@media screen and (max-width: 782px) {
	.admin-bar .tb-header { top: 46px; }
}

/* -------------------------------------------------------------------
 * BRANDMARK — wordmark with the strapline ruled beneath it
 *
 * The strapline has to be exactly as wide as the wordmark above it, and
 * the wordmark's width is not a number anyone can type: it changes with
 * the font size, with the condensed header state, and with whatever
 * TB_WORDMARK_SUFFIX happens to say.
 *
 * So the column sizes itself to the wordmark and the strapline is told
 * to fill it. `width: 0` removes the strapline from the intrinsic width
 * calculation — without it, a strapline longer than the wordmark would
 * set the column's width instead of the other way round — while
 * `min-width: 100%` makes it span whatever the wordmark decided.
 * ------------------------------------------------------------------- */

.tb-brandmark {
	display: inline-flex;
	flex-direction: column;
	align-items: stretch;
	gap: 0.2rem;
}

.tb-brandmark__strap {
	width: 0;
	min-width: 100%;
	font-family: var(--tb-font-body);

	/* Sized to the wordmark, not picked by eye.
	 *
	 * The wordmark grows from 202px to 294px across the breakpoint
	 * (--tb-display-hero-size steps 30px -> 48px), but this line was
	 * pinned at 9px. Measured: the text filled 95% of the mark on mobile
	 * — 2px per word gap — and only 65% on desktop, where justification
	 * had 102px to dump into four gaps at 25px each. That is the "so much
	 * space between words".
	 *
	 * 13px restores the desktop fill to 94%, which is the mobile look.
	 * The breakpoint matches the one in tb-tokens.css that moves the
	 * wordmark, so the two always step together. */
	font-size: 0.8125rem;   /* 13px, against a 48px wordmark */
	font-weight: 600;
	line-height: 1.2;
	text-transform: uppercase;
	color: var(--tb-ink-subtle);
	white-space: nowrap;

	/* Justify the last (and only) line so the words spread to both
	   edges. text-align alone does nothing to a single line — the last
	   line of a justified block is left-aligned by definition, and this
	   block is nothing but a last line. */
	text-align: justify;
	text-align-last: justify;
}

/* The condensed header shrinks the wordmark, so the strapline would sit
   under a narrower mark with the same type size and start to look
   oversized. It goes instead — the masthead is already stating less. */
.tb-header.is-condensed .tb-brandmark__strap {
	display: none;
}

/* Kept at tablet and phone widths — the strapline is the point of the
   lockup, and the wordmark is still wide enough there to justify across
   without the word gaps opening up. It goes only on the narrowest
   phones, where the mark shrinks far enough that five words stretched
   across it reads as broken spacing rather than a strapline. */
@media (max-width: 767px) {
	/* The wordmark steps down to 30px here, so the strapline steps with
	   it — same ratio, same tightness, same look. */
	.tb-brandmark__strap { font-size: 0.5625rem; }   /* 9px */
}

@media (max-width: 359px) {
	.tb-brandmark__strap { display: none; }
}

/* --- tb-article --- */
/**
 * Totoong Balita — Article
 * Single-post and static-page reading experience. Body copy is capped
 * to --tb-measure so line length stays readable at any viewport.
 */

.tb-article { min-width: 0; }
.tb-article--solo { max-width: var(--tb-measure); margin-inline: auto; }

/* --- Head -------------------------------------------------------- */
.tb-article__head {
	display: flex;
	flex-direction: column;
	gap: var(--tb-space-sm);
	padding-bottom: var(--tb-space-lg);
	margin-bottom: var(--tb-space-lg);
	border-bottom: var(--tb-rule);
}

.tb-article__title {
	font-family: var(--tb-font-headline);
	font-size: var(--tb-display-hero-size);
	line-height: var(--tb-display-hero-line);
	font-weight: var(--tb-display-hero-weight);
	letter-spacing: var(--tb-display-hero-track);
	color: var(--tb-ink);
	/* Wide enough that a long Tagalog headline doesn't stack into a
	   six-line column, tight enough to stay a headline and not a
	   paragraph. */
	max-width: 30ch;
}
@media (max-width: 1023px) { .tb-article__title { max-width: none; } }

.tb-article__deck {
	font-size: var(--tb-subhead-size);
	line-height: var(--tb-subhead-line);
	font-weight: var(--tb-subhead-weight);
	color: var(--tb-ink-muted);
	max-width: var(--tb-measure);
}

.tb-article__byline {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--tb-space-xs);
	font-size: var(--tb-timestamp-size);
	color: var(--tb-ink-subtle);
}

/* --- Lead image --------------------------------------------------- */
.tb-article__figure { margin-bottom: var(--tb-space-lg); }
.tb-article__caption {
	padding-top: var(--tb-space-xs);
	font-size: var(--tb-caption-size);
	line-height: var(--tb-caption-line);
	color: var(--tb-ink-subtle);
	border-bottom: var(--tb-rule);
	padding-bottom: var(--tb-space-xs);
}

/* --- Body copy ----------------------------------------------------
 * Generic element selectors, scoped to .tb-article__body, so pasted
 * editor content is styled without needing classes on every tag.
 * ----------------------------------------------------------------- */
.tb-article__body {
	max-width: var(--tb-measure);
	font-size: var(--tb-body-lg-size);
	line-height: var(--tb-body-lg-line);
	color: var(--tb-ink);
}

/* The flow rule: every block after the first gets space above it.
   Do NOT add `.tb-article__body p { margin: 0 }` back — an element
   selector inside the class beats `> * + *` on specificity and silently
   removes the spacing between consecutive paragraphs. The global reset
   already zeroes p margins, so it would be redundant as well as harmful. */
.tb-article__body > * + * { margin-top: var(--tb-space-md); }

.tb-article__body h2 {
	font-family: var(--tb-font-headline);
	font-size: var(--tb-headline-md-size);
	line-height: var(--tb-headline-md-line);
	font-weight: 700;
	margin-top: var(--tb-space-xl);
}
.tb-article__body h3 {
	font-family: var(--tb-font-headline);
	font-size: var(--tb-headline-sm-size);
	line-height: var(--tb-headline-sm-line);
	font-weight: 600;
	margin-top: var(--tb-space-lg);
}

.tb-article__body a {
	color: var(--tb-secondary);
	text-decoration: underline;
	text-underline-offset: 2px;
	transition: color var(--tb-duration-fast) var(--tb-ease);
}
.tb-article__body a:hover { color: var(--tb-tertiary); }

.tb-article__body ul,
.tb-article__body ol { padding-left: var(--tb-space-lg); }
.tb-article__body ul { list-style: disc; }
.tb-article__body ol { list-style: decimal; }
.tb-article__body li + li { margin-top: var(--tb-space-xs); }

.tb-article__body blockquote {
	padding-left: var(--tb-space-md);
	border-left: 3px solid var(--tb-primary);
	font-family: var(--tb-font-headline);
	font-size: var(--tb-headline-md-size);
	line-height: var(--tb-headline-md-line);
	font-style: italic;
	color: var(--tb-ink);
}

.tb-article__body figure { margin: var(--tb-space-lg) 0; }
.tb-article__body figcaption {
	padding-top: var(--tb-space-xs);
	font-size: var(--tb-caption-size);
	color: var(--tb-ink-subtle);
}

.tb-article__body img { width: 100%; height: auto; }

.tb-article__body hr {
	border-top: var(--tb-rule-strong);
	margin: var(--tb-space-xl) 0;
}

.tb-article__body table { font-size: var(--tb-body-md-size); }
.tb-article__body th,
.tb-article__body td {
	padding: var(--tb-space-xs) var(--tb-space-sm);
	border: var(--tb-rule);
	text-align: left;
}
.tb-article__body th { background: var(--tb-surface-sunken); font-weight: 600; }

.tb-article__body code {
	font-family: var(--tb-font-mono);
	font-size: 0.9em;
	background: var(--tb-surface-muted);
	padding: 0.1em 0.3em;
}
.tb-article__body pre {
	background: var(--tb-surface-inverse);
	color: var(--tb-ink-inverse);
	padding: var(--tb-space-md);
	overflow-x: auto;
}
.tb-article__body pre code { background: none; color: inherit; }

/* Embedded video keeps its aspect ratio */
.tb-article__body iframe { width: 100%; aspect-ratio: var(--tb-ratio-hero); height: auto; }

/* --- Tags --------------------------------------------------------- */
.tb-article__tags {
	margin-top: var(--tb-space-xl);
	padding-top: var(--tb-space-md);
	border-top: var(--tb-rule);
}


/* The related-stories block sits directly under the two-column layout.
   Both are flow siblings with no margin of their own, so without this
   the section rule lands hard against the end of the article. */
.tb-layout + .tb-section { margin-top: var(--tb-space-2xl); }

/* Byline separators as pseudo-elements.
   A separator that is its own flex item can wrap by itself, stranding a
   bullet at the end of a line — which is exactly what happened at phone
   width. Drawing it on the following item keeps the pair together. */
.tb-article__byline > * + *::before,
.tb-meta > * + *::before {
	content: "\2022";
	margin-right: var(--tb-space-xs);
	color: var(--tb-border-strong);
}

/* ===================================================================
 * FIGURES — caption and credit
 * Two different texts, so two different weights. The caption is
 * editorial copy; the credit is the record of who made the picture and
 * sits quieter without hiding.
 * ================================================================= */
.tb-figure { margin: 0; }
.tb-figure__cap {
	display: flex;
	flex-direction: column;
	gap: 2px;
	margin-top: var(--tb-space-xs);
}
.tb-figure__caption {
	font-size: var(--tb-caption-size);
	line-height: 1.5;
	color: var(--tb-ink-muted);
}
.tb-figure__credit {
	font-size: var(--tb-caption-size);
	letter-spacing: 0.02em;
	text-transform: uppercase;
	color: var(--tb-ink-faint);
}

/* ===================================================================
 * PHOTO STORY
 * A vertical stack, not a slideshow: one click per photograph is a
 * toll, and a single image in a carousel cannot be linked to.
 * ================================================================= */
.tb-gallery {
	display: flex;
	flex-direction: column;
	gap: var(--tb-space-lg);
	margin-top: var(--tb-space-lg);
	padding-top: var(--tb-space-lg);
	border-top: var(--tb-rule);
}
.tb-gallery__item { min-width: 0; }

/* The image is the button. No frame of its own — a hover ring would
   put chrome around a photograph, which is the one thing a picture
   page should not do. */
.tb-figure__open {
	display: block;
	width: 100%;
	padding: 0;
	border: 0;
	background: none;
	cursor: zoom-in;
	line-height: 0;
}
.tb-figure__open:focus-visible {
	outline: var(--tb-focus-ring);
	outline-offset: var(--tb-focus-offset);
}
.tb-figure__img { width: 100%; height: auto; display: block; }

/* --- Lightbox ------------------------------------------------------ */
.tb-lightbox {
	width: 100vw;
	max-width: 100vw;
	height: 100vh;
	max-height: 100vh;
	margin: 0;
	padding: 0;
	border: 0;
	background: var(--tb-surface-inverse);
	color: var(--tb-ink-inverse);
}
.tb-lightbox::backdrop { background: rgba(17, 20, 24, 0.9); }

.tb-lightbox__inner {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: var(--tb-space-sm);
	height: 100%;
	margin: 0;
	/* Clear of the bar above and the arrows either side — the arrows
	   are 3rem wide and sit on the edge, so the picture starts past
	   them rather than under them. */
	padding: 3.5rem 4.5rem var(--tb-space-lg);
}
.tb-lightbox__inner img {
	max-width: 100%;
	/* Room for the caption underneath, so a long one never pushes the
	   photograph off the screen it was opened to fill. */
	max-height: calc(100vh - 10rem);
	object-fit: contain;
}
.tb-lightbox__cap {
	display: flex;
	flex-direction: column;
	gap: 2px;
	max-width: 44rem;
	text-align: center;
}
.tb-lightbox__cap .tb-figure__caption { color: var(--tb-ink-inverse); }
.tb-lightbox__cap .tb-figure__credit { color: var(--tb-ink-inverse-muted); }
.tb-lightbox__cap:empty { display: none; }

/* Counter and close, on one line above the picture. */
.tb-lightbox__bar {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	z-index: 1;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--tb-space-sm);
	padding: var(--tb-space-sm);
}
.tb-lightbox__count {
	font-size: var(--tb-caption-size);
	font-variant-numeric: tabular-nums;
	letter-spacing: var(--tb-label-track);
	color: var(--tb-ink-inverse-muted);
}
.tb-lightbox__close {
	display: inline-flex;
	padding: var(--tb-space-xxs);
	border: 0;
	background: none;
	color: var(--tb-ink-inverse);
	cursor: pointer;
}
.tb-lightbox__close svg { width: 28px; height: 28px; }

/* --- Moving through the set ----------------------------------------
   Big targets pinned to the sides: on a phone this is thumb territory,
   and a small arrow floating near the picture is a miss waiting to
   happen. */
.tb-lightbox__nav {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	z-index: 1;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 3rem;
	height: 3rem;
	border: 0;
	background: rgba(17, 20, 24, 0.5);
	color: var(--tb-ink-inverse);
	cursor: pointer;
	transition: background-color var(--tb-duration-fast) var(--tb-ease),
	            opacity var(--tb-duration-fast) var(--tb-ease);
}
.tb-lightbox__nav:hover { background: rgba(17, 20, 24, 0.75); }
.tb-lightbox__nav--prev { left: var(--tb-space-sm); }
.tb-lightbox__nav--next { right: var(--tb-space-sm); }
.tb-lightbox__nav svg { width: 24px; height: 24px; }

/* Plainly unavailable at the ends, rather than moving or vanishing
   under the thumb that was just reaching for it. */
.tb-lightbox__nav[disabled] { opacity: 0.25; cursor: default; }
.tb-lightbox__nav[disabled]:hover { background: rgba(17, 20, 24, 0.5); }

@media (max-width: 599px) {
	.tb-lightbox__nav { width: 2.5rem; height: 2.5rem; }
	.tb-lightbox__nav--prev { left: 0; }
	.tb-lightbox__nav--next { right: 0; }
	/* On a phone the arrows overlay the picture rather than insetting
	   it — screen width is the scarce thing here, not clearance. */
	.tb-lightbox__inner { padding: 3rem var(--tb-space-sm) var(--tb-space-md); }
}

/* Native video. The player is the browser's own — WordPress's
   MediaElement build is 180KB whose job is giving <video> to browsers
   that do not have it, and every browser a reader arrives with does. */
.tb-video {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: var(--tb-ratio-hero);
	background: var(--tb-surface-inverse);
}
.tb-article__video { margin-bottom: var(--tb-space-lg); }

/* ===================================================================
 * SOURCE CARD
 * A pasted link to another outlet's story. Built as a card rather
 * than left as an oEmbed iframe so the whole thing is one anchor the
 * reader can open in a new tab — see tb-links.php for why the iframe
 * could not be made to do that.
 *
 * Deliberately quieter than a pull quote and plainer than our own
 * story cards: it is a citation, and it should not compete with the
 * article it sits inside or be mistaken for our own reporting.
 * ================================================================= */
.tb-srccard { margin: var(--tb-space-lg) 0; }

.tb-srccard__link {
	display: flex;
	flex-direction: column;
	gap: 2px;
	padding: var(--tb-space-sm) var(--tb-space-md);
	border-left: 3px solid var(--tb-border-strong);
	background: var(--tb-surface-sunken);
	transition: border-color var(--tb-duration-fast) var(--tb-ease),
	            background var(--tb-duration-fast) var(--tb-ease);
}
/* The body-link rule is .tb-article__body a — one class and one
   element, which outranks a lone .tb-srccard__link, so the card came
   out underlined in our own link colour. Matched at the same depth to
   win it back. Underlining is wrong here because the target is the
   whole card, not the words. */
.tb-article__body .tb-srccard__link,
.tb-srccard__link {
	text-decoration: none;
	color: inherit;
}

.tb-srccard__link:hover,
.tb-srccard__link:focus-visible {
	border-left-color: var(--tb-primary);
	background: var(--tb-surface-muted);
}

.tb-srccard__kicker {
	font-size: var(--tb-timestamp-size);
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--tb-ink-subtle);
}

.tb-srccard__title {
	font-family: var(--tb-font-headline);
	font-size: var(--tb-headline-sm-size);
	line-height: var(--tb-headline-sm-line);
	color: var(--tb-ink);
}
.tb-article__body .tb-srccard__link:hover .tb-srccard__title,
.tb-srccard__link:hover .tb-srccard__title { color: var(--tb-secondary); }

.tb-srccard__host {
	font-size: var(--tb-caption-size);
	color: var(--tb-ink-subtle);
}

/* --- tb-pages --- */
/**
 * Totoong Balita — Static Pages, Forms, Weather, Consent
 * Loads on pages that need it: the standing pages, and anywhere the
 * weather panel or consent banner appears.
 */

/* ===================================================================
 * PAGE FURNITURE
 * ================================================================= */

/* Opening paragraph on a standing page — larger, lighter. */
.tb-article__body .tb-lede,
.tb-formpage__intro .tb-lede {
	font-family: var(--tb-font-body);
	font-size: var(--tb-subhead-size);
	line-height: 1.6;
	font-weight: var(--tb-subhead-weight);
	color: var(--tb-ink-muted);
	padding-bottom: var(--tb-space-md);
	margin-bottom: var(--tb-space-md);
	border-bottom: var(--tb-rule);
}

/* Sibling-page nav at the foot of a policy. */
.tb-pagenav {
	margin-top: var(--tb-space-2xl);
	padding-top: var(--tb-space-md);
	border-top: var(--tb-rule);
}
.tb-pagenav__title {
	font-size: var(--tb-label-size);
	font-weight: var(--tb-label-weight);
	letter-spacing: var(--tb-label-track);
	text-transform: uppercase;
	color: var(--tb-ink-subtle);
	margin-bottom: var(--tb-space-sm);
}

/* The editor-only "not yet reviewed" flag. */
.tb-legal-review { margin-bottom: var(--tb-space-lg); }
.tb-legal-review p + p { margin-top: var(--tb-space-xs); }

/* ===================================================================
 * FORM PAGES — copy on the left, form on the right
 * ================================================================= */
.tb-formpage {
	display: grid;
	gap: var(--tb-space-xl);
	grid-template-columns: 1fr;
	align-items: start;
}
@media (min-width: 1024px) {
	.tb-formpage {
		grid-template-columns: minmax(0, 1fr) 26rem;
		gap: var(--tb-space-2xl);
	}
	/* The form tracks the reader down a long page of copy. */
	.tb-formpage__form {
		position: sticky;
		top: calc(var(--tb-header-sticky, var(--tb-header-height)) + var(--tb-space-md));
	}
}

.tb-formpage__intro { min-width: 0; }
.tb-formpage__intro .tb-article__title { margin-bottom: var(--tb-space-md); }

.tb-formcard {
	background: var(--tb-surface-sunken);
	border: var(--tb-rule);
	border-top: 3px solid var(--tb-primary);
	padding: var(--tb-space-lg);
}
.tb-formcard__title {
	font-family: var(--tb-font-headline);
	font-size: var(--tb-headline-md-size);
	line-height: var(--tb-headline-md-line);
	font-weight: 600;
	margin-bottom: var(--tb-space-md);
}

.tb-formgrid {
	display: grid;
	gap: var(--tb-space-sm);
	grid-template-columns: 1fr;
}
@media (min-width: 560px) {
	.tb-formgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.tb-field__label span[aria-hidden] { color: var(--tb-primary); }

/* Honeypot. Hidden from people without display:none, which some bots
   check for, and kept out of the tab order and the a11y tree. */
.tb-trap {
	position: absolute !important;
	left: -9999px !important;
	top: auto;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

/* Audience figures on the advertise page. */
.tb-statrow {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: var(--tb-space-md);
	padding-block: var(--tb-space-md);
	margin-bottom: var(--tb-space-md);
	border-block: var(--tb-rule);
}
.tb-statrow__item { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.tb-statrow__num {
	font-family: var(--tb-font-headline);
	font-size: var(--tb-headline-lg-size);
	line-height: 1.1;
	font-weight: 700;
	color: var(--tb-primary);
	font-variant-numeric: tabular-nums;
}
.tb-statrow__label {
	font-size: var(--tb-caption-size);
	line-height: 1.35;
	color: var(--tb-ink-subtle);
}

/* ===================================================================
 * WEATHER
 * ================================================================= */
.tb-wx { display: flex; flex-direction: column; }

.tb-wx__row {
	display: grid;
	grid-template-columns: 1.75rem 1fr auto;
	align-items: center;
	gap: var(--tb-space-sm);
	padding-block: var(--tb-space-xs);
	border-bottom: var(--tb-rule);
}
.tb-wx__row:last-child { border-bottom: none; }

.tb-wx__glyph { display: flex; color: var(--tb-tertiary); }
.tb-wx__icon { width: 22px; height: 22px; }

.tb-wx__place { display: flex; flex-direction: column; min-width: 0; }
.tb-wx__place strong {
	font-size: var(--tb-body-sm-size);
	font-weight: 600;
	color: var(--tb-ink);
}
.tb-wx__place span {
	font-size: var(--tb-caption-size);
	color: var(--tb-ink-subtle);
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.tb-wx__temp {
	font-family: var(--tb-font-headline);
	font-size: var(--tb-headline-sm-size);
	font-weight: 700;
	color: var(--tb-ink);
	font-variant-numeric: tabular-nums;
}

.tb-wx__more {
	display: inline-block;
	margin-top: var(--tb-space-sm);
	font-size: var(--tb-body-sm-size);
	font-weight: 600;
	color: var(--tb-secondary);
}
.tb-wx__more:hover { text-decoration: underline; }

/* ===================================================================
 * COOKIE CONSENT
 * A bar, not a modal: it doesn't trap the reader or block the story.
 * ================================================================= */
.tb-consent {
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: var(--tb-z-modal);
	background: var(--tb-surface-inverse);
	color: var(--tb-ink-inverse);
	border-top: 3px solid var(--tb-primary);
	animation: tb-consent-in var(--tb-duration) var(--tb-ease);
}

@keyframes tb-consent-in {
	from { transform: translateY(100%); }
	to   { transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
	.tb-consent { animation: none; }
}

.tb-consent__inner {
	max-width: var(--tb-container-max);
	margin-inline: auto;
	padding: var(--tb-space-md) var(--tb-gutter);
	display: flex;
	flex-direction: column;
	gap: var(--tb-space-sm);
}
@media (min-width: 768px) {
	.tb-consent__inner {
		flex-direction: row;
		align-items: center;
		justify-content: space-between;
		gap: var(--tb-space-lg);
	}
}

.tb-consent__text {
	font-size: var(--tb-body-sm-size);
	line-height: 1.5;
	color: var(--tb-ink-inverse-muted);
}
.tb-consent__text strong { color: var(--tb-ink-inverse); }
.tb-consent__link { margin-top: var(--tb-space-xxs); }
.tb-consent__link a {
	color: var(--tb-ink-inverse);
	text-decoration: underline;
	font-size: var(--tb-caption-size);
}

/* Both choices are real buttons at the same size. Rejecting is exactly
   as easy as accepting. */
.tb-consent__actions {
	display: flex;
	gap: var(--tb-space-xs);
	flex-shrink: 0;
}
.tb-consent__actions .tb-btn { flex: 1; white-space: nowrap; }
@media (min-width: 768px) {
	.tb-consent__actions .tb-btn { flex: 0 0 auto; min-width: 9rem; }
}
.tb-consent__actions .tb-btn--outline {
	background: transparent;
	color: var(--tb-ink-inverse);
	border-color: var(--tb-border-inverse);
}
.tb-consent__actions .tb-btn--outline:hover { background: var(--tb-surface-inverse-alt); }

.tb-consent-reset { cursor: pointer; }

/* ===================================================================
 * AUTH PAGES — login, reset, invitation
 * A single centred card. No masthead competition, no sidebar.
 * ================================================================= */
.tb-auth {
	max-width: 27rem;
	margin-inline: auto;
	padding-block: var(--tb-space-xl) var(--tb-space-3xl);
}

.tb-auth__card {
	background: var(--tb-surface);
	border: var(--tb-rule-strong);
	border-top: 3px solid var(--tb-primary);
	padding: var(--tb-space-xl) var(--tb-space-lg);
}

.tb-auth__brand {
	display: block;
	font-family: var(--tb-font-headline);
	font-size: var(--tb-headline-lg-size);
	line-height: 1;
	font-weight: 700;
	letter-spacing: -0.015em;
	color: var(--tb-primary);
}
.tb-auth__brand span {
	font-size: var(--tb-headline-md-size);
	font-style: italic;
	font-weight: 400;
	letter-spacing: normal;
	color: var(--tb-ink);
	margin-left: 0.15em;
}

.tb-auth__edition {
	margin-top: var(--tb-space-xxs);
	padding-bottom: var(--tb-space-lg);
	margin-bottom: var(--tb-space-lg);
	border-bottom: var(--tb-rule);
	font-size: var(--tb-label-size);
	font-weight: var(--tb-label-weight);
	letter-spacing: var(--tb-label-track);
	text-transform: uppercase;
	color: var(--tb-ink-subtle);
}

.tb-auth__title {
	font-family: var(--tb-font-headline);
	font-size: var(--tb-headline-md-size);
	line-height: var(--tb-headline-md-line);
	font-weight: 700;
	color: var(--tb-ink);
	margin-bottom: var(--tb-space-xs);
}
.tb-auth__subtitle {
	font-size: var(--tb-body-sm-size);
	line-height: 1.5;
	color: var(--tb-ink-muted);
	margin-bottom: var(--tb-space-md);
}

.tb-auth__remember {
	display: flex;
	align-items: center;
	gap: var(--tb-space-xs);
	font-size: var(--tb-body-sm-size);
	color: var(--tb-ink-muted);
	cursor: pointer;
}
.tb-auth__remember input { accent-color: var(--tb-primary); }

.tb-auth__footer {
	margin-top: var(--tb-space-md);
	text-align: center;
	font-size: var(--tb-body-sm-size);
	color: var(--tb-ink-subtle);
}
.tb-auth__footer a { color: var(--tb-secondary); font-weight: 500; }
.tb-auth__footer a:hover { text-decoration: underline; }

/* Invitation summary — what you're accepting, before you accept it. */
.tb-auth__invite {
	display: flex;
	flex-direction: column;
	gap: var(--tb-space-xs);
	padding: var(--tb-space-sm) var(--tb-space-md);
	margin-bottom: var(--tb-space-md);
	background: var(--tb-surface-sunken);
	border-left: 3px solid var(--tb-secondary);
}
.tb-auth__invite > div {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	gap: var(--tb-space-sm);
}
.tb-auth__invite span {
	font-size: var(--tb-label-size);
	font-weight: var(--tb-label-weight);
	letter-spacing: var(--tb-label-track);
	text-transform: uppercase;
	color: var(--tb-ink-subtle);
}
.tb-auth__invite strong {
	font-size: var(--tb-body-sm-size);
	color: var(--tb-ink);
	text-align: right;
	word-break: break-word;
}

/* Password field with an inline reveal. */
.tb-pwfield { position: relative; display: flex; align-items: center; }
.tb-pwfield .tb-input { padding-right: 4.5rem; }
.tb-pwfield__toggle {
	position: absolute;
	right: var(--tb-space-xs);
	padding: var(--tb-space-xxs) var(--tb-space-xs);
	font-size: var(--tb-caption-size);
	font-weight: 700;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--tb-secondary);
	background: var(--tb-surface);
}
.tb-pwfield__toggle:hover { color: var(--tb-primary); }

/* Role descriptions under the invite form. */
.tb-nr-rolehelp {
	padding: var(--tb-space-sm) var(--tb-space-md);
	background: var(--tb-surface-sunken);
	border-left: 3px solid var(--tb-border-strong);
	font-size: var(--tb-caption-size);
	line-height: 1.5;
	color: var(--tb-ink-muted);
}
.tb-nr-rolehelp p + p { margin-top: var(--tb-space-xxs); }

.tb-select--sm {
	width: auto;
	padding-block: var(--tb-space-xxs);
	font-size: var(--tb-body-sm-size);
}

/* ===================================================================
 * AVATARS
 * One of the two sanctioned circles in the system (the other is the
 * live pip). A writer's face earns it.
 * ================================================================= */
.tb-avatar {
	display: block;
	width: 4rem;
	height: 4rem;
	border-radius: var(--tb-radius-circle);
	object-fit: cover;
	background: var(--tb-surface-muted);
	flex-shrink: 0;
}

/* No Gravatar fallback — an initial on a solid disc beats a stranger's
   default avatar, and loads nothing third-party. */
.tb-avatar--initial {
	display: flex;
	align-items: center;
	justify-content: center;
	background: var(--tb-secondary);
	color: var(--tb-on-secondary);
	font-family: var(--tb-font-headline);
	font-size: 1.5rem;
	font-weight: 700;
	line-height: 1;
}

/* ===================================================================
 * AUTHOR CARD — under an article
 * ================================================================= */
.tb-authorcard {
	display: flex;
	gap: var(--tb-space-md);
	align-items: flex-start;
	margin-top: var(--tb-space-xl);
	padding-top: var(--tb-space-lg);
	border-top: var(--tb-rule-strong);
}

.tb-authorcard__media { flex-shrink: 0; }
.tb-authorcard__body { min-width: 0; display: flex; flex-direction: column; gap: var(--tb-space-xxs); }

.tb-authorcard__name {
	font-family: var(--tb-font-headline);
	font-size: var(--tb-headline-sm-size);
	line-height: var(--tb-headline-sm-line);
	font-weight: 700;
	color: var(--tb-ink);
}
.tb-authorcard__name a:hover { color: var(--tb-secondary); }

.tb-authorcard__role {
	font-size: var(--tb-caption-size);
	color: var(--tb-ink-subtle);
}
.tb-authorcard__bio {
	font-size: var(--tb-body-sm-size);
	line-height: 1.55;
	color: var(--tb-ink-muted);
	margin-top: var(--tb-space-xxs);
}
.tb-authorcard__more {
	margin-top: var(--tb-space-xxs);
	font-size: var(--tb-body-sm-size);
	font-weight: 600;
}
.tb-authorcard__more a { color: var(--tb-secondary); }
.tb-authorcard__more a:hover { text-decoration: underline; }

/* ===================================================================
 * AUTHOR ARCHIVE HERO
 * ================================================================= */
.tb-authorhero {
	display: flex;
	gap: var(--tb-space-lg);
	align-items: flex-start;
	padding-bottom: var(--tb-space-lg);
	margin-bottom: var(--tb-space-xl);
	border-bottom: var(--tb-rule-strong);
}
@media (max-width: 639px) {
	.tb-authorhero { flex-direction: column; gap: var(--tb-space-md); }
}

.tb-authorhero__media { flex-shrink: 0; }
.tb-authorhero__media .tb-avatar { width: 6rem; height: 6rem; }
.tb-authorhero__media .tb-avatar--initial { font-size: 2.25rem; }

.tb-authorhero__body { min-width: 0; display: flex; flex-direction: column; gap: var(--tb-space-xxs); }

.tb-authorhero__name {
	font-family: var(--tb-font-headline);
	font-size: var(--tb-headline-lg-size);
	line-height: var(--tb-headline-lg-line);
	font-weight: 700;
	letter-spacing: var(--tb-headline-lg-track);
	color: var(--tb-ink);
}
.tb-authorhero__role {
	font-size: var(--tb-subhead-size);
	font-weight: var(--tb-subhead-weight);
	color: var(--tb-ink-muted);
}
.tb-authorhero__bio {
	font-size: var(--tb-body-md-size);
	line-height: 1.6;
	color: var(--tb-ink-muted);
	max-width: 62ch;
	margin-top: var(--tb-space-xs);
}

.tb-authorhero__meta {
	display: flex;
	flex-wrap: wrap;
	gap: var(--tb-space-md);
	margin-top: var(--tb-space-sm);
	padding-top: var(--tb-space-sm);
	border-top: var(--tb-rule);
	font-size: var(--tb-caption-size);
	color: var(--tb-ink-subtle);
}
.tb-authorhero__meta strong { color: var(--tb-ink); font-size: var(--tb-body-sm-size); }
.tb-authorhero__meta a { color: var(--tb-secondary); }
.tb-authorhero__meta a:hover { text-decoration: underline; }

/* ===================================================================
 * SHARE
 * Plain links, no third-party widgets — nothing here can track a reader.
 * ================================================================= */
.tb-share {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: var(--tb-space-sm);
	padding-block: var(--tb-space-sm);
}
.tb-share--inline {
	border-block: var(--tb-rule);
	margin-bottom: var(--tb-space-lg);
}
/* The second row, shown only on a long read — see tb_is_long_read(). */
.tb-share--footer {
	border-top: var(--tb-rule);
	margin-top: var(--tb-space-lg);
}

.tb-share__label {
	font-size: var(--tb-label-size);
	font-weight: var(--tb-label-weight);
	letter-spacing: var(--tb-label-track);
	text-transform: uppercase;
	color: var(--tb-ink-subtle);
	flex-shrink: 0;
}

.tb-share__buttons { display: flex; flex-wrap: wrap; gap: var(--tb-space-xs); }

/* Icon only, so square rather than a pill with one glyph rattling
   around in it. The names are on aria-label and title. */
.tb-share__btn {
	position: relative;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 2.25rem;
	height: 2.25rem;
	padding: 0;
	border: var(--tb-rule-strong);
	border-radius: var(--tb-radius);
	background: var(--tb-surface);
	color: var(--tb-ink-muted);
	cursor: pointer;
	transition: background-color var(--tb-duration-fast) var(--tb-ease),
	            border-color var(--tb-duration-fast) var(--tb-ease),
	            color var(--tb-duration-fast) var(--tb-ease);
}
.tb-share__btn svg { width: 17px; height: 17px; }

/* Each target takes its own brand colour on hover only — the resting
   state stays neutral so the row doesn't shout over the headline. */
.tb-share__btn:hover { border-color: currentColor; }
.tb-share__btn--facebook:hover { color: #1877f2; }
.tb-share__btn--x:hover        { color: var(--tb-ink); }
.tb-share__btn--copy:hover     { color: var(--tb-secondary); }

.tb-share__btn:focus-visible {
	outline: var(--tb-focus-ring);
	outline-offset: var(--tb-focus-offset);
}

/* "Nakopya!" — the copy button has no text of its own to swap, so the
   confirmation is drawn here from the attribute the script sets. */
.tb-share__btn[data-tb-copied]::after {
	content: attr(data-tb-copied);
	position: absolute;
	bottom: calc(100% + var(--tb-space-xxs));
	left: 50%;
	transform: translateX(-50%);
	z-index: var(--tb-z-sticky);
	padding: 2px var(--tb-space-xxs);
	background: var(--tb-surface-inverse);
	color: var(--tb-ink-inverse);
	font-size: var(--tb-caption-size);
	font-weight: 600;
	white-space: nowrap;
	pointer-events: none;
}
.tb-share__btn[data-tb-copied] { color: var(--tb-secondary); }

/* ===================================================================
 * BREAKING BANNER
 * Above the masthead, so it is the first thing on the page.
 * ================================================================= */
.tb-breakingbar {
	background: var(--tb-primary);
	color: var(--tb-on-primary);
}
.tb-breakingbar__inner { display: flex; align-items: center; }

.tb-breakingbar__link {
	display: flex;
	align-items: center;
	gap: var(--tb-space-sm);
	padding-block: var(--tb-space-xs);
	min-width: 0;
	color: var(--tb-on-primary);
	width: 100%;
}
a.tb-breakingbar__link:hover .tb-breaking__text { text-decoration: underline; }

.tb-breaking__tag {
	display: inline-flex;
	align-items: center;
	gap: var(--tb-space-xxs);
	flex-shrink: 0;
	font-size: var(--tb-label-size);
	font-weight: var(--tb-label-weight);
	letter-spacing: var(--tb-label-track);
	text-transform: uppercase;
}
/* --- One line, always ----------------------------------------------
 * The text lives in a clipping viewport so it can travel when it is
 * too long for the bar, the way a broadcast crawl does. It only moves
 * if it has to: tb-ui.js measures and adds .is-scrolling, so a short
 * alert never budges.
 *
 * The still state is the default, which is also what a reader without
 * JavaScript gets — one line, ellipsis, no wrap. The mobile override
 * that used to let this wrap to three lines is gone: it pushed the
 * masthead down the page, and truncating instead cut the sentence
 * exactly where an evacuation alert names the towns.
 * ------------------------------------------------------------------ */
.tb-breaking__viewport {
	flex: 1;
	min-width: 0;
	overflow: hidden;
}

.tb-breaking__track {
	display: flex;
	min-width: 0;
}

.tb-breaking__text {
	font-size: var(--tb-body-sm-size);
	font-weight: 500;
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* --- Moving, because it did not fit -------------------------------- */
.tb-breakingbar.is-scrolling .tb-breaking__track {
	width: max-content;
	animation: tb-breaking-scroll var(--tb-breaking-duration, 20s) linear infinite;
}
/* No ellipsis while travelling — the end of the sentence is coming. */
.tb-breakingbar.is-scrolling .tb-breaking__text {
	overflow: visible;
	text-overflow: clip;
	padding-right: 3rem;
}

/* The track carries the sentence twice, so -50% lands the copy where
   the original started and the loop does not snap back. */
@keyframes tb-breaking-scroll {
	from { transform: translateX(0); }
	to   { transform: translateX(-50%); }
}

/* Stop while it is being read, tabbed through, or switched off. */
.tb-breakingbar:hover .tb-breaking__track,
.tb-breakingbar:focus-within .tb-breaking__track,
.tb-breakingbar.is-paused .tb-breaking__track {
	animation-play-state: paused;
}

/* --- Pause control, same two-bar/triangle icon as the ticker ------- */
.tb-breaking__toggle {
	flex-shrink: 0;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 1.5rem;
	height: 1.5rem;
	margin-left: var(--tb-space-xs);
	color: var(--tb-on-primary);
	opacity: 0.85;
}
.tb-breaking__toggle:hover { opacity: 1; }
.tb-breaking__toggle[hidden] { display: none; }

.tb-breaking__toggle-icon {
	width: 8px;
	height: 9px;
	border-left: 3px solid currentColor;
	border-right: 3px solid currentColor;
}
.tb-breakingbar.is-paused .tb-breaking__toggle-icon {
	width: 0;
	height: 0;
	border-left: 8px solid currentColor;
	border-right: 0;
	border-top: 5px solid transparent;
	border-bottom: 5px solid transparent;
}

/* Reduced motion: nothing moves. The viewport becomes a strip the
   reader can push sideways themselves, and the duplicate sentence is
   hidden so it is not there twice. */
@media (prefers-reduced-motion: reduce) {
	.tb-breakingbar.is-scrolling .tb-breaking__viewport {
		overflow-x: auto;
		scrollbar-width: none;
	}
	.tb-breakingbar.is-scrolling .tb-breaking__viewport::-webkit-scrollbar { display: none; }
	.tb-breakingbar.is-scrolling .tb-breaking__track { animation: none; }
	.tb-breaking__text[aria-hidden="true"] { display: none; }
	.tb-breaking__toggle { display: none; }
}

/* ===================================================================
 * CORRECTIONS
 * ================================================================= */
.tb-corrections {
	margin-block: var(--tb-space-lg);
	padding: var(--tb-space-md);
	background: var(--tb-surface-sunken);
	border: var(--tb-rule);
}

/* A retraction sits above the story and has to look unlike the story. */
.tb-corrections--top {
	background: var(--tb-error-tint);
	border-color: var(--tb-error);
	border-left: 3px solid var(--tb-error);
}

.tb-corrections__title {
	font-size: var(--tb-label-size);
	font-weight: var(--tb-label-weight);
	letter-spacing: var(--tb-label-track);
	text-transform: uppercase;
	color: var(--tb-ink-subtle);
	padding-bottom: var(--tb-space-xs);
	margin-bottom: var(--tb-space-sm);
	border-bottom: var(--tb-rule);
}
.tb-corrections--top .tb-corrections__title { color: var(--tb-error); border-bottom-color: var(--tb-error); }

.tb-correction + .tb-correction {
	margin-top: var(--tb-space-sm);
	padding-top: var(--tb-space-sm);
	border-top: var(--tb-rule);
}
.tb-correction__head {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: var(--tb-space-sm);
	margin-bottom: var(--tb-space-xxs);
}
.tb-correction__label {
	font-size: var(--tb-label-size);
	font-weight: var(--tb-label-weight);
	letter-spacing: var(--tb-label-track);
	text-transform: uppercase;
	color: var(--tb-primary);
}
.tb-correction.is-retraction .tb-correction__label { color: var(--tb-error); }
.tb-correction.is-update .tb-correction__label     { color: var(--tb-secondary); }
.tb-correction__head time { font-size: var(--tb-caption-size); color: var(--tb-ink-subtle); }

.tb-correction__text {
	font-size: var(--tb-body-md-size);
	line-height: 1.6;
	color: var(--tb-ink);
}
.tb-correction__by { font-size: var(--tb-caption-size); color: var(--tb-ink-subtle); margin-top: var(--tb-space-xxs); }

.tb-corrections__policy {
	margin-top: var(--tb-space-sm);
	padding-top: var(--tb-space-sm);
	border-top: var(--tb-rule);
	font-size: var(--tb-caption-size);
	color: var(--tb-ink-subtle);
}
.tb-corrections__policy a { color: var(--tb-secondary); text-decoration: underline; }

.tb-article__updated { color: var(--tb-primary); font-weight: 500; }

/* ===================================================================
 * LIVE BLOG
 * ================================================================= */
.tb-live {
	margin-block: var(--tb-space-xl);
	padding-top: var(--tb-space-md);
	border-top: 3px solid var(--tb-primary);
}

.tb-live__head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--tb-space-sm);
	flex-wrap: wrap;
	margin-bottom: var(--tb-space-md);
}

.tb-live__status {
	display: inline-flex;
	align-items: center;
	gap: var(--tb-space-xxs);
	padding: var(--tb-space-xxs) var(--tb-space-sm);
	font-size: var(--tb-label-size);
	font-weight: var(--tb-label-weight);
	letter-spacing: var(--tb-label-track);
	text-transform: uppercase;
}
.tb-live__status.is-live  { background: var(--tb-primary); color: var(--tb-on-primary); }
.tb-live__status.is-ended { background: var(--tb-surface-muted); color: var(--tb-ink-subtle); }

.tb-live__count { font-size: var(--tb-caption-size); color: var(--tb-ink-subtle); }

.tb-live__new { margin-bottom: var(--tb-space-md); }

.tb-live__list { display: flex; flex-direction: column; list-style: none; }

/* The rail: a vertical line with a node per update, which is what makes
   a sequence of updates read as a timeline rather than a list. */
.tb-live__item {
	position: relative;
	display: grid;
	grid-template-columns: 5rem minmax(0, 1fr);
	gap: var(--tb-space-md);
	padding-bottom: var(--tb-space-lg);
}
@media (max-width: 639px) {
	.tb-live__item { grid-template-columns: 1fr; gap: var(--tb-space-xxs); }
}

.tb-live__item::before {
	content: "";
	position: absolute;
	left: 5rem;
	/* Starts at the node's centre, so the line runs out of the dot
	   rather than crossing it. */
	top: 0.7rem;
	bottom: 0;
	width: 1px;
	background: var(--tb-border);
	transform: translateX(-0.5px);
}
.tb-live__item:last-child::before { bottom: auto; height: 0; }
@media (max-width: 639px) { .tb-live__item::before { display: none; } }

.tb-live__meta {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 2px;
	position: relative;
}
@media (max-width: 639px) {
	.tb-live__meta { flex-direction: row; align-items: baseline; gap: var(--tb-space-xs); }
}

/* The node, centred on the rail.
 *
 * It was offset by the grid gap plus 4px, which put it past the rail
 * and 4px into the content column — landing on the first letter of
 * every update. It only looked right on a pinned one, because that
 * body has padding of its own for the dot to sit in.
 *
 * Anchored to the meta column's right edge and pulled back by half its
 * own width, so it sits on the line whatever the gap is set to. */
.tb-live__meta::after {
	content: "";
	position: absolute;
	right: 0;
	top: 0.3rem;
	transform: translateX(50%);
	width: 9px;
	height: 9px;
	border-radius: var(--tb-radius-circle);
	background: var(--tb-primary);
	border: 2px solid var(--tb-surface);
}
@media (max-width: 639px) { .tb-live__meta::after { display: none; } }

.tb-live__meta time {
	font-family: var(--tb-font-body);
	font-size: var(--tb-body-sm-size);
	font-weight: 700;
	color: var(--tb-ink);
	font-variant-numeric: tabular-nums;
}
.tb-live__date { font-size: var(--tb-caption-size); color: var(--tb-ink-subtle); }
.tb-live__pin {
	font-size: 10px;
	font-weight: 700;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--tb-primary);
}

.tb-live__title {
	font-family: var(--tb-font-headline);
	font-size: var(--tb-headline-sm-size);
	line-height: var(--tb-headline-sm-line);
	font-weight: 700;
	margin-bottom: var(--tb-space-xxs);
}
.tb-live__body { font-size: var(--tb-body-md-size); line-height: 1.6; color: var(--tb-ink); }
.tb-live__body p + p { margin-top: var(--tb-space-xs); }
.tb-live__by { font-size: var(--tb-caption-size); color: var(--tb-ink-subtle); margin-top: var(--tb-space-xs); }

.tb-live__item.is-pinned .tb-live__body {
	padding: var(--tb-space-sm) var(--tb-space-md);
	background: var(--tb-surface-sunken);
	border-left: 3px solid var(--tb-primary);
}

.tb-live__empty { font-size: var(--tb-body-md-size); color: var(--tb-ink-subtle); }

/* ===================================================================
 * FRONT-END EDIT LINK
 * Replaces the one useful thing the admin bar did, without putting a
 * band across the top of the masthead. Staff only.
 * ================================================================= */
.tb-editlink {
	position: fixed;
	right: var(--tb-space-md);
	bottom: var(--tb-space-md);
	z-index: var(--tb-z-sticky);
	display: inline-flex;
	align-items: center;
	gap: var(--tb-space-xs);
	padding: var(--tb-space-xs) var(--tb-space-md);
	background: var(--tb-surface-inverse);
	color: var(--tb-ink-inverse);
	font-family: var(--tb-font-body);
	font-size: var(--tb-body-sm-size);
	font-weight: 600;
	border-radius: var(--tb-radius);
	box-shadow: 0 2px 12px rgba(17, 20, 24, 0.22);
	transition: background-color var(--tb-duration-fast) var(--tb-ease);
}
.tb-editlink:hover { background: var(--tb-primary); }
.tb-editlink svg { width: 15px; height: 15px; }

/* A live blog is the one case where the edit route needs to be obvious —
   updates are the story. */
.tb-editlink.is-live { background: var(--tb-primary); }
.tb-editlink.is-live:hover { background: var(--tb-primary-dark); }

.tb-editlink__badge {
	display: inline-flex;
	align-items: center;
	padding: 1px var(--tb-space-xxs);
	background: var(--tb-on-primary);
	color: var(--tb-primary);
	font-size: 10px;
	font-weight: 700;
	letter-spacing: 0.06em;
	text-transform: uppercase;
}

/* The consent bar occupies the same corner; lift the button clear of it. */
.tb-consent ~ .tb-editlink,
body:has(.tb-consent) .tb-editlink { bottom: 6rem; }

@media (max-width: 479px) {
	/* Icon only on the narrowest screens, so it never covers content. */
	.tb-editlink__label { display: none; }
	.tb-editlink { padding: var(--tb-space-xs); }
}

/* ===================================================================
 * THE COVERAGE MAP — /lugar/
 * Where is a beat for a regional newsroom, so it gets a page that says
 * plainly which places we file from.
 * ================================================================= */
.tb-places { display: flex; flex-direction: column; gap: var(--tb-space-xl); }

.tb-places__grid {
	display: grid;
	gap: var(--tb-space-md);
	grid-template-columns: 1fr;
	margin-top: var(--tb-space-md);
}
@media (min-width: 640px)  { .tb-places__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .tb-places__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.tb-places__prov {
	padding: var(--tb-space-sm) var(--tb-space-md);
	border-left: 3px solid var(--tb-primary);
	background: var(--tb-surface-sunken);
}
.tb-places__prov-name {
	display: flex;
	align-items: baseline;
	gap: var(--tb-space-xs);
	font-family: var(--tb-font-headline);
	font-size: var(--tb-headline-sm-size);
	font-weight: 700;
	color: var(--tb-ink);
}
.tb-places__prov-name:hover { color: var(--tb-primary); }

/* How many stories we have filed from there — quiet, and absent when
   the answer is none rather than printing a zero. */
.tb-places__n {
	font-family: var(--tb-font-body);
	font-size: var(--tb-caption-size);
	font-weight: 600;
	color: var(--tb-ink-faint);
	font-variant-numeric: tabular-nums;
}

.tb-places__towns {
	display: flex;
	flex-wrap: wrap;
	gap: var(--tb-space-xxs) var(--tb-space-xs);
	margin-top: var(--tb-space-xs);
}
.tb-places__towns a {
	font-size: var(--tb-caption-size);
	color: var(--tb-ink-muted);
}
.tb-places__towns a:hover { color: var(--tb-primary); text-decoration: underline; }

.tb-footer__more { font-weight: 600; }

