/* Goald web app — the design tokens and the rules that read them.
   The tokens themselves are no longer hand-rolled here: they are
   generated from `design/tokens.toml`, the one source the mobile
   shells and the admin panel read too, into the marked block below.
   The design language is the mobile app's: light surfaces, a
   magenta/pink brand colour, dark-violet chrome, and Bai Jamjuree
   throughout. Light-first, with the dark override the generator emits
   beneath the light values. No CSS framework dependency — keeps the
   wasm bundle and build graph small. */

/* Bai Jamjuree, self-hosted (SIL OFL 1.1 — /OFL.txt). The font files
   sit at the dist root: see index.html for why they must not live
   under a subdirectory. Weights 400/500/600/700 — the family tops out
   at 700; the mobile app's heavier strokes are synthesised. */

@font-face {
	font-family: "Bai Jamjuree";
	font-style: normal;
	font-weight: 400;
	font-display: swap;
	src: url("/bai-jamjuree-latin-400.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: "Bai Jamjuree";
	font-style: normal;
	font-weight: 400;
	font-display: swap;
	src: url("/bai-jamjuree-latin-ext-400.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: "Bai Jamjuree";
	font-style: normal;
	font-weight: 500;
	font-display: swap;
	src: url("/bai-jamjuree-latin-500.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: "Bai Jamjuree";
	font-style: normal;
	font-weight: 500;
	font-display: swap;
	src: url("/bai-jamjuree-latin-ext-500.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: "Bai Jamjuree";
	font-style: normal;
	font-weight: 600;
	font-display: swap;
	src: url("/bai-jamjuree-latin-600.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: "Bai Jamjuree";
	font-style: normal;
	font-weight: 600;
	font-display: swap;
	src: url("/bai-jamjuree-latin-ext-600.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: "Bai Jamjuree";
	font-style: normal;
	font-weight: 700;
	font-display: swap;
	src: url("/bai-jamjuree-latin-700.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: "Bai Jamjuree";
	font-style: normal;
	font-weight: 700;
	font-display: swap;
	src: url("/bai-jamjuree-latin-ext-700.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;
}

/* The design tokens below are GENERATED from `design/tokens.toml` by
   `cargo run -p design-tokens --bin generate`, which writes the same
   block into both web stylesheets and into the Swift and Kotlin
   surfaces beside them. Do not hand-edit between the markers — edit
   the source and regenerate; `cargo test -p design-tokens` fails if
   the two disagree. Everything outside the markers is hand-written
   and the generator leaves it alone. */

/* GENERATED TOKENS BEGIN */
:root {
	/* ---- Palette: the literal swatches, exact hex ---- */
	/* The brand pink: every call to action, on light and dark alike.
	   Darkened from the shipped `#EC0A8C` on 2026-09-14 by the
	   smallest step that carries white label text over the 4.5:1
	   body-text floor (4.21:1 -> 4.58:1), holding hue and saturation. */
	--colour-pink: #E10A86;
	--colour-magenta: #A0016B;
	/* The magenta lifted for dark surfaces: the same hue at half the
	   saturation and twice the lightness, so magenta text clears 4.5:1
	   on the dark page, card and sunken fills alike. */
	--colour-magenta-light: #C969A9;
	--colour-indigo: #20034B;
	/* The indigo lifted for dark surfaces the same way: the same hue
	   at half the saturation, its lightness raised until heading ink
	   clears 4.5:1 on the dark page, card and sunken fills alike. */
	--colour-lavender: #9C7ACF;
	/* The Goald Gradient's middle stop. Referenced by the gradients
	   hand-written beneath this block and by nothing else — a gradient
	   is a value, not a token, so it is not generated. */
	--colour-gradient-mid: #5B0356;
	--colour-violet-deep: #1A0340;
	--colour-ink-violet: #23083A;
	--colour-violet-mist: #6A5A8A;
	--colour-prize-gold: #E8B33C;
	--colour-impact-green: #00C46A;
	/* Darkened from the shipped `#ED4C5C` on 2026-09-14: white label
	   text on the destructive button measured 3.63:1 and now measures
	   4.56:1. The smallest lightness step that clears the floor while
	   holding BOTH hue and saturation (354.0 degrees, 0.82), so the
	   danger colour stays a red rather than softening towards a
	   brick — the owner's call between the two ways down. */
	--colour-error-red: #E8192E;
	--colour-text-muted: #6B6280;
	--colour-sunken: #F3F3F3;
	--colour-raised: #FCFCFC;
	--colour-header: #F8F8F8;
	--colour-grey-divider: #D9D9D9;
	/* The decorative hairline: a card's edge, a table rule, a tab
	   strip. NOT a control boundary — that is `grey-boundary` below,
	   and the two are separate swatches precisely so the boundary can
	   be strong enough to identify a control without every hairline
	   in both apps darkening with it. */
	--colour-grey-border: #E7E7E7;
	/* The control boundary: the lightest grey that identifies a text
	   field against the white page at the 3:1 non-text floor
	   (3.07:1, where the `#E7E7E7` hairline measures 1.24:1). */
	--colour-grey-boundary: #939393;
	--colour-picton-blue: #34ACEE;
	--colour-silver: #B3B9C4;
	--colour-bronze: #C1680F;
	--colour-white: #FFFFFF;

	/* The award-style organisation-page swatches. */
	--colour-award-purple-deep: #361453;
	--colour-award-purple: #532A78;
	--colour-award-magenta: #E400B7;
	--colour-award-gold: #F3BA25;
	--colour-award-navy: #15133E;
	--colour-award-sky: #00BCFE;

	/* The dark-appearance swatches: the violet-tinted surface and ink
	   ramps the dark override reaches for. Nothing outside that
	   override references them. */
	--colour-dark-page: #170B1D;
	--colour-dark-raised: #21112B;
	--colour-dark-sunken: #100716;
	--colour-dark-header: #1D0E25;
	--colour-dark-border: #3A2547;
	/* The control boundary in the dark appearance — `grey-boundary`'s
	   counterpart, and derived the same way: `dark-border`'s own hue
	   raised until the boundary clears 3:1 against the dark page
	   (3.06:1, where the `#3A2547` hairline measures 1.39:1). */
	--colour-violet-boundary: #7B4E96;
	--colour-dark-ink: #F3F3F3;
	--colour-dark-muted: #B6A9BF;

	/* ---- Semantic layer: the role names every surface reads ---- */
	--colour-page: var(--colour-white);
	/* A card, a sheet, a table row: the surface that sits above the
	   page. */
	--colour-page-raised: var(--colour-raised);
	/* A well beneath the page: a secondary button, an idle chip, an
	   input group's backing. */
	--colour-page-sunken: var(--colour-sunken);
	--colour-page-header: var(--colour-header);
	--colour-ink: var(--colour-ink-violet);
	--colour-ink-muted: var(--colour-text-muted);
	/* Text and glyphs drawn on an accent or danger fill. */
	--colour-on-accent: var(--colour-white);
	--colour-accent: var(--colour-pink);
	/* The quieter half of the accent pair: a secondary button's label,
	   a pressed state. The deep magenta on light; the lifted magenta
	   on dark, where the deep one is unreadable on the sunken fill
	   this label sits on. */
	--colour-accent-muted: var(--colour-magenta);
	/* The heading's quieter partner: a secondary heading, a secondary
	   action. Takes the same two magentas as `accent-muted`, for the
	   same reason — a heading has to be readable in both appearances. */
	--colour-subheading: var(--colour-magenta);
	/* A page or section title, an author's name, a statistic's value,
	   a chip's or a badge's label: the ink a heading is set in. The
	   deep indigo on light; the lavender lifted from it on dark, where
	   the indigo disappears into the surface behind it. */
	--colour-heading: var(--colour-indigo);
	/* Fixed chrome: the nav bar and the sidebar stay dark violet in
	   both appearances, which is why this entry has no dark form of its
	   own. */
	--colour-nav-bar: var(--colour-violet-deep);
	--colour-nav-idle: var(--colour-violet-mist);
	--colour-nav-bar-border: rgb(255 255 255 / 20%);
	/* The decorative hairline every container and separator draws:
	   card, tile, table, tab strip, the nav bar's edges. A boundary
	   that IDENTIFIES a control is `field-border` instead — the split
	   is what keeps a control legible without darkening every
	   hairline in both apps. */
	--colour-border: var(--colour-grey-border);
	/* The boundary that identifies an input: strong enough to clear
	   SC 1.4.11's 3:1 floor against the page in both appearances,
	   which a hairline is not. The `field` treatment and the
	   stylesheets' own input rules are its only readers. */
	--colour-field-border: var(--colour-grey-boundary);
	--colour-divider: var(--colour-grey-divider);
	/* The hairline around a raised surface: ink at a tenth on light,
	   white at a tenth on dark. */
	--colour-card-edge: rgb(35 8 58 / 10%);
	--colour-prize: var(--colour-prize-gold);
	--colour-impact: var(--colour-impact-green);
	--colour-danger: var(--colour-error-red);
	--colour-on-danger: var(--colour-white);
	--colour-rank-first: var(--colour-award-gold);
	--colour-rank-second: var(--colour-silver);
	--colour-rank-third: var(--colour-bronze);
	--colour-info: var(--colour-picton-blue);
	/* The wash behind a modal or a sheet. */
	--colour-scrim: rgb(26 16 48 / 8%);
	/* The colour a drop shadow is drawn in — the `--shadow-card` value
	   hand-written beneath this block composes it. Equal to the scrim
	   today; separate because one is a wash over content and the other
	   is a shadow under it, and they will not stay equal. */
	--colour-shadow: rgb(26 16 48 / 8%);

	/* The organisation-page roles. The award-style palette is the
	   design's own vocabulary, and these name the part each swatch
	   plays on that page rather than the colour it happens to be. */
	--colour-award-surface-deep: var(--colour-award-purple-deep);
	--colour-award-surface: var(--colour-award-purple);
	--colour-award-action: var(--colour-award-magenta);
	--colour-award-highlight: var(--colour-award-gold);
	--colour-award-ink: var(--colour-award-navy);
	--colour-award-pill: var(--colour-award-sky);

	/* ---- Type ---- */

	/* Bai Jamjuree throughout, self-hosted by the web surfaces and
	   bundled by the shells. THE FACE CARRIES LATIN AND LATIN-EXTENDED
	   ONLY: Cyrillic, Devanagari, Bengali, Japanese and Simplified
	   Chinese all render in whichever fallback face the platform picks,
	   and no per-script stack is declared anywhere. That is a recorded
	   gap for the owner, not a decision — the stack below is one
	   family, and inventing a per-script vocabulary here would put an
	   untested answer in front of a design question nobody has asked
	   yet. */
	--font-sans: "Bai Jamjuree", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
	--font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
	--font-size-display: 32px;
	--font-size-h1: 24px;
	--font-size-h2: 20px;
	--font-size-h3: 18px;
	--font-size-body: 15px;
	--font-size-small: 13px;
	--font-size-caption: 11px;
	--weight-regular: 400;
	--weight-medium: 500;
	--weight-semibold: 600;
	/* The family tops out at 700; heavier strokes are synthesised. */
	--weight-bold: 700;

	/* ---- Shape: 5px chips, 10px buttons / inputs / cards, 16px
	   sheets, and the pill ---- */
	--radius-sm: 5px;
	--radius-md: 10px;
	--radius-lg: 16px;
	--radius-pill: 999px;

	/* ---- Spacing ---- */

	/* Declared here in PIXELS — one number every surface shares, and
	   what the shells want verbatim (`Dp`, `CGFloat`). The web writer
	   is the one place that converts, dividing by the 16px root font
	   size to emit `rem`: a gap in `px` ignores the reader's own base
	   font size, so a page spaced entirely in `px` stops growing when
	   someone enlarges their browser's default text. One declaration,
	   both truths — never a second spacing scale in rem. */
	--space-1: 0.25rem;
	--space-2: 0.5rem;
	--space-3: 0.75rem;
	--space-4: 1rem;
	--space-6: 1.5rem;
	--space-8: 2rem;

	/* ---- Fixed sizes: the dimensions that are neither spacing nor
	   type, so no shell carries a raw number of its own ---- */
	/* A button's and a field's touch target. */
	--size-control-height: 50px;
	--size-avatar: 40px;
	--size-avatar-sm: 36px;
	--size-avatar-lg: 88px;
	--size-tab-chip: 36px;

	/* ---- Opacity ---- */
	/* The dimming every disabled control shares, so all four surfaces
	   dim by the same amount. */
	--opacity-disabled: 0.5;

	/* ---- Component contract ---- */

	/* The primary action: a filled accent button with white text. Its
	   label is UPPERCASED — a presentational rule the schema has no
	   field for, recorded here and applied by each surface's own text
	   transform. */
	--primary-button-fill: var(--colour-accent);
	--primary-button-text: var(--colour-on-accent);
	--primary-button-radius: var(--radius-md);
	--primary-button-height: var(--size-control-height);
	--primary-button-label-size: var(--font-size-body);
	--primary-button-label-weight: var(--weight-bold);

	/* The secondary action: the same shape on the sunken fill, its
	   label in the muted accent. */
	--secondary-button-fill: var(--colour-page-sunken);
	--secondary-button-text: var(--colour-accent-muted);
	--secondary-button-radius: var(--radius-md);
	--secondary-button-height: var(--size-control-height);
	--secondary-button-label-size: var(--font-size-body);
	--secondary-button-label-weight: var(--weight-bold);

	/* A destructive action: the same shape in the danger colour. Its
	   own treatment rather than a flag on the primary one, so a safe
	   default can never sit on a destructive action. */
	--destructive-button-fill: var(--colour-danger);
	--destructive-button-text: var(--colour-on-danger);
	--destructive-button-radius: var(--radius-md);
	--destructive-button-height: var(--size-control-height);
	--destructive-button-label-size: var(--font-size-body);
	--destructive-button-label-weight: var(--weight-bold);

	/* A single-line text input: ink on the raised surface, inside the
	   boundary that identifies it, at the control height. */
	--field-fill: var(--colour-page-raised);
	--field-text: var(--colour-ink);
	--field-border: var(--colour-field-border);
	--field-border-width: 1px;
	--field-radius: var(--radius-md);
	--field-height: var(--size-control-height);

	/* The content card: the raised surface behind the card edge,
	   padded on the spacing scale. */
	--card-fill: var(--colour-page-raised);
	--card-border: var(--colour-card-edge);
	--card-border-width: 1px;
	--card-radius: var(--radius-md);
	--card-padding-horizontal: var(--space-4);
	--card-padding-vertical: var(--space-4);

	/* A small label on the sunken fill, at the chip radius. */
	--chip-fill: var(--colour-page-sunken);
	--chip-text: var(--colour-heading);
	--chip-radius: var(--radius-sm);

	/* The chip's rounded form: the same colours at the pill radius. */
	--badge-fill: var(--colour-page-sunken);
	--badge-text: var(--colour-heading);
	--badge-radius: var(--radius-pill);

	/* A tab in a chip row: a fixed-height chip filled with the deep
	   violet chrome colour, carrying on-accent text. The per-tab blue,
	   green, gold and bronze fills a screen may apply are SCREEN-LEVEL
	   MODIFIERS on this one treatment, not treatments of their own —
	   the violet declared here is the tab's own colour, and what the
	   contrast gate measures the on-accent text against.

	   It reads `nav-bar` rather than `heading`, which it carried until
	   2026-09-14: this is a FILL under white glyphs, not heading ink,
	   and the two roles part company in the dark appearance, where a
	   heading has to lighten and a fill under white content must not. */
	--tab-chip-fill: var(--colour-nav-bar);
	--tab-chip-text: var(--colour-on-accent);
	--tab-chip-radius: var(--radius-sm);
	--tab-chip-height: var(--size-tab-chip);

	/* The page itself: ink on the page fill. */
	--page-fill: var(--colour-page);
	--page-text: var(--colour-ink);
}

/* The dark appearance. Only the colours whose dark form differs from
   their light form are re-declared here; every other entry keeps its
   light value in both, a recorded design gap until dark mode is
   designed rather than a claim that it already has been. */
@media (prefers-color-scheme: dark) {
	:root {
		--colour-page: var(--colour-dark-page);
		--colour-page-raised: var(--colour-dark-raised);
		--colour-page-sunken: var(--colour-dark-sunken);
		--colour-page-header: var(--colour-dark-header);
		--colour-ink: var(--colour-dark-ink);
		--colour-ink-muted: var(--colour-dark-muted);
		--colour-accent-muted: var(--colour-magenta-light);
		--colour-subheading: var(--colour-magenta-light);
		--colour-heading: var(--colour-lavender);
		--colour-border: var(--colour-dark-border);
		--colour-field-border: var(--colour-violet-boundary);
		--colour-divider: var(--colour-dark-border);
		--colour-card-edge: rgb(255 255 255 / 10%);
		--colour-scrim: rgb(0 0 0 / 40%);
		--colour-shadow: rgb(0 0 0 / 40%);
	}
}
/* GENERATED TOKENS END */

/* Hand-written, immediately beneath the generated block: a gradient
   and a box-shadow are composed VALUES, not tokens — the generator
   emits the colours they compose, and these spell out how they
   compose them. The stops are PALETTE swatches rather than semantic
   roles deliberately: a brand gradient is one fixed asset in both
   appearances, where the roles that used to supply the auth
   gradient's two ends — `subheading` and `heading` — lighten in the
   dark one. */
:root {
	--gradient-auth:
		linear-gradient(100deg, var(--colour-magenta) 0%, var(--colour-gradient-mid) 45%, var(--colour-indigo) 100%); /* the Goald Gradient — the only purple */
	--gradient-brand-blue:  linear-gradient(160deg, #ad0ca0, #67a9eb); /* bluePinkGradient — its two stops are its own */
	--gradient-org-featured:
		linear-gradient(135deg, var(--colour-award-surface-deep), var(--colour-award-surface) 50%, var(--colour-award-action)); /* featured card top */
	--gradient-org-tile:    linear-gradient(135deg, var(--colour-award-ink), var(--colour-award-surface)); /* pledge-row thumbnail fallback */

	--shadow-card:          0 2px 3px var(--colour-shadow);
}

* {
	box-sizing: border-box;
}

html,
body {
	margin: 0;
	padding: 0;
	height: 100%;
	background: var(--colour-page);
	color: var(--colour-ink);
	font-family: var(--font-sans);
	font-size: 15px;
	line-height: 1.5;
}

a {
	color: var(--colour-accent);
	font-weight: 600;
}

button,
input,
select,
textarea {
	font: inherit;
	color: inherit;
}

/* App shell: sticky top nav + centred content column. */

.app-shell {
	min-height: 100vh;
	display: flex;
	flex-direction: column;
}

.app-topnav {
	position: sticky;
	top: 0;
	z-index: 10;
	display: flex;
	align-items: center;
	gap: var(--space-2);
	flex-wrap: wrap;
	padding: var(--space-2) var(--space-4);
	background: var(--colour-page);
	border-bottom: 1px solid var(--colour-border);
}

.app-topnav__brand {
	font-weight: 700;
	font-size: 1.25rem;
	color: var(--colour-accent);
	margin-right: var(--space-4);
	text-decoration: none;
}

.app-topnav a {
	padding: var(--space-1) var(--space-3);
	border-radius: var(--radius-md);
	color: var(--colour-nav-idle);
	font-weight: 600;
	text-decoration: none;
}

/* The brand wordmark is exempt from the link pill treatment — it is
   also an `<A href="/">`, so it would otherwise carry the active pill
   whenever the feed is open. */

.app-topnav a:hover:not(.app-topnav__brand),
.app-topnav a.active:not(.app-topnav__brand),
.app-topnav a[aria-current]:not(.app-topnav__brand) {
	background: var(--colour-page-sunken);
	color: var(--colour-accent);
}

.app-topnav__links {
	display: contents;
}

.app-topnav__spacer {
	flex: 1;
}

/* The unread-count pill shared by the top nav's Notifications link
   and the bottom nav's bell. */

.app-nav__badge {
	display: inline-block;
	background: var(--colour-accent);
	color: #ffffff;
	border-radius: 999px;
	font-size: 0.7rem;
	font-weight: 700;
	line-height: 1.2;
	padding: 0 0.35rem;
	min-width: 1rem;
	text-align: center;
	vertical-align: top;
}

/* The bottom navigation — the mobile app's five-tab bar. Hidden on
   wide viewports; fixed to the bottom edge on narrow ones. Active =
   pink, inactive = the mobile bar's muted violet. */

.app-bottomnav {
	display: none;
}

@media (max-width: 720px) {
	.app-topnav__links {
		display: none;
	}

	.app-bottomnav {
		position: fixed;
		bottom: 0;
		left: 0;
		right: 0;
		z-index: 10;
		display: flex;
		justify-content: space-around;
		align-items: stretch;
		background: var(--colour-page);
		border-top: 1px solid var(--colour-border);
		padding: var(--space-1) 0 calc(var(--space-1) + env(safe-area-inset-bottom));
	}

	/* Keep the content clear of the fixed bar. */
	.app-main {
		padding-bottom: calc(var(--space-8) + 64px);
	}
}

.app-bottomnav a {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 2px;
	padding: var(--space-1) var(--space-2);
	color: var(--colour-nav-idle);
	text-decoration: none;
	font-size: 0.75rem;
	font-weight: 700;
}

.app-bottomnav a svg {
	width: 24px;
	height: 24px;
}

.app-bottomnav a[aria-current],
.app-bottomnav a.active {
	color: var(--colour-accent);
}

.app-bottomnav__icon {
	position: relative;
	display: flex;
}

.app-bottomnav__icon .app-nav__badge {
	position: absolute;
	top: -4px;
	right: -10px;
}

.app-main {
	width: 100%;
	max-width: 860px;
	margin: 0 auto;
	padding: var(--space-6) var(--space-4) var(--space-8);
}

.page-title {
	font-size: 1.45rem;
	font-weight: 700;
	color: var(--colour-heading);
	margin: 0 0 var(--space-4);
}

.section-title {
	font-size: 1.1rem;
	font-weight: 700;
	color: var(--colour-heading);
	margin: var(--space-6) 0 var(--space-3);
}


.card {
	background: var(--colour-page-raised);
	border: 1px solid var(--colour-border);
	border-radius: var(--radius-md);
	box-shadow: var(--shadow-card);
	padding: var(--space-4);
}

.card + .card {
	margin-top: var(--space-4);
}

.card-title {
	font-weight: 700;
	margin: 0 0 var(--space-2);
}

/* The trending feed — single column of mobile-style feed cards: a
   dark-violet author bar over a brand-magenta body strip, mirroring
   the mobile app's feed-card anatomy. */

.feed-list {
	display: flex;
	flex-direction: column;
	gap: var(--space-4);
}

.feed-card {
	display: block;
	border-radius: var(--radius-md);
	overflow: hidden;
	box-shadow: var(--shadow-card);
	text-decoration: none;
}

.feed-card:hover {
	filter: brightness(1.05);
}

.feed-card__author {
	display: flex;
	align-items: center;
	gap: var(--space-2);
	background: var(--colour-nav-bar);
	padding: var(--space-2) var(--space-3);
}

.feed-card__author-text {
	display: flex;
	flex-direction: column;
	line-height: 1.3;
}

.feed-card__username {
	color: #ffffff;
	font-weight: 700;
	font-size: 0.95rem;
}

.feed-card__subtitle {
	color: rgb(255 255 255 / 60%);
	font-weight: 600;
	font-size: 0.8rem;
}

.feed-card__body {
	background: var(--colour-accent);
	color: #ffffff;
	padding: var(--space-3);
}

.feed-card__title {
	font-weight: 700;
	font-size: 1.05rem;
}

/* Author rows on light surfaces (submission cards, lists). */

.author-row {
	display: flex;
	align-items: center;
	gap: var(--space-2);
	margin-bottom: var(--space-3);
}

.author-row__text {
	display: flex;
	flex-direction: column;
	line-height: 1.3;
}

.author-row__name {
	font-weight: 700;
	color: var(--colour-heading);
	text-decoration: none;
}

.author-row__subtitle {
	font-size: 0.8rem;
	font-weight: 600;
	color: var(--colour-ink-muted);
}


/* The verified tick — the mobile pattern: a green check on a
   dark-violet disc, inline after the name. */

.verified-tick {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 18px;
	height: 18px;
	border-radius: 50%;
	background: var(--colour-nav-bar);
	color: var(--colour-impact);
	vertical-align: middle;
	margin-left: var(--space-1);
}

.verified-tick svg {
	width: 12px;
	height: 12px;
}

/* Feed / entity grids. */

.tile-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
	gap: var(--space-4);
}

.tile {
	display: block;
	background: var(--colour-page-raised);
	border: 1px solid var(--colour-border);
	border-radius: var(--radius-md);
	box-shadow: var(--shadow-card);
	padding: var(--space-4);
	color: var(--colour-ink);
	font-weight: 400;
	text-decoration: none;
}

.tile:hover {
	border-color: var(--colour-accent);
}

.tile__title {
	font-weight: 700;
	margin-bottom: var(--space-1);
}

.tile__meta {
	color: var(--colour-ink-muted);
	font-size: 0.85rem;
}

/* Video playback. */

.video-frame {
	display: block;
	width: 100%;
	max-width: 420px;
	max-height: 70vh;
	/* Overridden inline (`style=("aspect-ratio", …)`) once the media's
	   real width/height are known; this is the pre-metadata / unknown-
	   dimensions fallback — portrait 9:16 is this app's common case. */
	aspect-ratio: 9 / 16;
	margin: 0 auto;
	background: #000;
	border-radius: var(--radius-md);
	object-fit: contain;
}

/* The click-to-play poster shown in place of a video until first
   interaction — nothing streams until it is clicked. Shares the
   .video-frame footprint and reuses the .video-tile__play overlay. */

.video-poster {
	position: relative;
	padding: 0;
	border: none;
	cursor: pointer;
}

.video-poster img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: contain;
}

.video-placeholder {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	max-width: 420px;
	min-height: 200px;
	margin: 0 auto;
	background: var(--colour-page-sunken);
	border: 1px dashed var(--colour-divider);
	border-radius: var(--radius-md);
	color: var(--colour-ink-muted);
}

/* Stats / metrics. */

.stat-grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
	gap: var(--space-4);
	margin-bottom: var(--space-6);
}

.stat-tile {
	background: var(--colour-page-raised);
	border: 1px solid var(--colour-border);
	border-radius: var(--radius-md);
	box-shadow: var(--shadow-card);
	padding: var(--space-4);
}

.stat-tile__label {
	color: var(--colour-ink-muted);
	font-size: 0.8rem;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.03em;
}

.stat-tile__value {
	font-size: 1.6rem;
	font-weight: 700;
	color: var(--colour-accent);
	margin-top: var(--space-1);
}

/* Tables (leaderboards, lists). */

table {
	width: 100%;
	border-collapse: collapse;
	font-size: 0.9rem;
}

th,
td {
	text-align: left;
	padding: var(--space-2) var(--space-3);
	border-bottom: 1px solid var(--colour-border);
	white-space: nowrap;
}

th {
	color: var(--colour-ink-muted);
	font-weight: 600;
	font-size: 0.75rem;
	text-transform: uppercase;
	letter-spacing: 0.03em;
}

.table-scroll {
	overflow-x: auto;
	background: var(--colour-page-raised);
	border: 1px solid var(--colour-border);
	border-radius: var(--radius-md);
	box-shadow: var(--shadow-card);
}

/* Buttons, inputs, forms — the mobile shapes: 10px radius, filled,
   borderless, uppercase-bold CTAs (PrimaryActionButton). */

.btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--space-2);
	background: var(--colour-page-sunken);
	border: none;
	border-radius: var(--radius-md);
	color: var(--colour-accent-muted);
	font-weight: 700;
	padding: var(--space-2) var(--space-4);
	cursor: pointer;
	text-decoration: none;
}


.btn:hover {
	filter: brightness(0.96);
}

.btn:disabled {
	opacity: 0.5;
	cursor: not-allowed;
}

.btn-primary {
	background: var(--colour-accent);
	color: #ffffff;
	text-transform: uppercase;
	letter-spacing: 0.02em;
}

.btn-primary:hover {
	filter: brightness(1.05);
}

.btn-danger {
	background: var(--colour-danger);
	color: var(--colour-on-danger);
}

.input {
	background: var(--colour-page-raised);
	border: 1px solid var(--colour-field-border);
	border-radius: var(--radius-md);
	box-shadow: var(--shadow-card);
	color: var(--colour-ink);
	padding: var(--space-2) var(--space-4);
}

.input::placeholder {
	color: var(--colour-ink-muted);
	font-weight: 500;
}

.input:focus {
	outline: 2px solid var(--colour-accent);
	outline-offset: -1px;
}

textarea.input {
	min-height: 5rem;
	resize: vertical;
}

.field {
	display: flex;
	flex-direction: column;
	gap: var(--space-1);
	margin-bottom: var(--space-3);
}

.field label {
	font-size: 0.8rem;
	font-weight: 600;
	color: var(--colour-ink-muted);
}

.form-actions {
	display: flex;
	gap: var(--space-2);
	margin-top: var(--space-4);
}

/* Badges, banners, chrome. The green badge follows the mobile
   pattern: guppieGreen fill with darkViolet content (verified ticks,
   highlighted spans). */

.badge {
	display: inline-block;
	padding: 0.15rem 0.6rem;
	border-radius: 999px;
	font-size: 0.75rem;
	font-weight: 700;
	background: var(--colour-page-sunken);
	color: var(--colour-heading);
}


.badge-success {
	background: var(--colour-impact);
	color: var(--colour-nav-bar);
}

/* Dark-violet text, like .badge-success — white on the mustard
   yellow fails contrast. */
.badge-warning {
	background: var(--colour-prize);
	color: var(--colour-nav-bar);
}

.badge-danger {
	background: var(--colour-danger);
	color: var(--colour-on-danger);
}

.badge-accent {
	background: var(--colour-accent);
	color: #ffffff;
}

/* The trophy cabinet: the tally header line, medal chips (the medal
   colour tokens — dark-violet content, as white fails contrast on
   gold and silver), and one row per held award. */

.trophy-tally {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2);
	margin: var(--space-4) 0;
}

.medal-badge {
	display: inline-block;
	padding: 0.15rem 0.6rem;
	border-radius: 999px;
	font-size: 0.75rem;
	font-weight: 700;
	background: var(--colour-page-sunken);
	color: var(--colour-nav-bar);
}

.medal-badge--gold {
	background: var(--colour-rank-first);
}

.medal-badge--silver {
	background: var(--colour-rank-second);
}

.medal-badge--bronze {
	background: var(--colour-rank-third);
	color: #ffffff;
}

.trophy-row {
	display: flex;
	align-items: center;
	gap: var(--space-3);
	padding: var(--space-2) 0;
}

.trophy-row + .trophy-row {
	border-top: 1px solid var(--colour-border);
}

/* The shared signed-out affordance: "Sign in to …" rendered in place
   of an auth-required control. On the branded organisation hero the
   muted grey fails contrast, so it goes white there. */

.signin-prompt {
	margin: var(--space-2) 0;
	font-size: 0.875rem;
}

.org-hero .signin-prompt,
.org-hero .signin-prompt a {
	color: #ffffff;
}

/* The signed-out store nudge: "Get the Goald app" over two text-only
   badge buttons (dark-violet pills echoing the official store-badge
   anatomy — small hint line over the store name; no image assets). */

.store-nudge {
	margin-top: auto;
	padding: var(--space-6) var(--space-4) var(--space-8);
	border-top: 1px solid var(--colour-border);
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--space-3);
	text-align: center;
}

.store-nudge__text {
	font-weight: 700;
}

.store-nudge__badges {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: var(--space-3);
}

.store-badge {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	min-width: 9.5rem;
	padding: var(--space-2) var(--space-4);
	border-radius: var(--radius-md);
	background: var(--colour-nav-bar);
	color: #ffffff;
	text-decoration: none;
	line-height: 1.25;
}

.store-badge__hint {
	font-size: 0.65rem;
	text-transform: uppercase;
	letter-spacing: 0.05em;
	opacity: 0.85;
}

.store-badge__store {
	font-size: 1.05rem;
	font-weight: 700;
}

.report-action {
	margin-top: var(--space-2);
}

.report-action select.input {
	width: auto;
	flex: 1;
	min-width: 0;
}

.error-banner {
	background: color-mix(in srgb, var(--colour-danger) 12%, var(--colour-page-raised));
	border: 1px solid var(--colour-danger);
	color: var(--colour-ink);
	border-radius: var(--radius-md);
	padding: var(--space-3);
	margin-bottom: var(--space-4);
}

.notice-banner {
	background: color-mix(in srgb, var(--colour-impact) 15%, var(--colour-page-raised));
	border: 1px solid var(--colour-impact);
	color: var(--colour-ink);
	border-radius: var(--radius-md);
	padding: var(--space-3);
	margin-bottom: var(--space-4);
}

/* Auth (login / register) shell — the mobile login look: full-bleed
   purple→pink gradient, white heading, floating white inputs, pink
   CTA. */

.auth-shell {
	min-height: 100vh;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: var(--space-4);
	background: var(--gradient-auth);
}

.auth-card {
	width: 360px;
	max-width: 100%;
	display: flex;
	flex-direction: column;
	gap: var(--space-2);
}

.auth-brand {
	font-size: 2rem;
	font-weight: 700;
	color: #ffffff;
	text-align: center;
	margin: 0 0 var(--space-4);
}

.auth-intro {
	color: rgb(255 255 255 / 85%);
	text-align: center;
	margin: 0 0 var(--space-2);
}

/* The auth form floats directly on the gradient, mobile-style: white
   floating inputs (always white, whatever the colour scheme), white
   labels, green links (the mobile register screen's link colour). */

.auth-card .field label {
	color: rgb(255 255 255 / 85%);
}

.auth-card .input {
	background: #ffffff;
	color: #171717;
	border: none;
	box-shadow: 0 4px 12px rgb(0 0 0 / 20%);
}

.auth-card .input::placeholder {
	color: #808080;
}

.auth-toggle {
	text-align: center;
	margin-top: var(--space-2);
	color: rgb(255 255 255 / 85%);
}

.auth-toggle .muted {
	color: rgb(255 255 255 / 85%);
}

.auth-toggle a {
	color: var(--colour-impact);
	font-weight: 600;
}

.auth-legal {
	font-size: 0.75rem;
	color: rgb(255 255 255 / 70%);
	text-align: center;
	margin: var(--space-2) 0 0;
}

.auth-legal a {
	color: var(--colour-impact);
}

.legal-links {
	text-align: center;
	margin-top: var(--space-4);
}

.legal-links a {
	color: inherit;
	text-decoration: underline;
}

/* Misc. */

.toolbar {
	display: flex;
	gap: var(--space-2);
	align-items: center;
	margin-bottom: var(--space-4);
	flex-wrap: wrap;
}

.tabs {
	display: flex;
	gap: var(--space-2);
	border-bottom: 1px solid var(--colour-border);
	margin-bottom: var(--space-4);
}

.tabs button {
	background: none;
	border: none;
	border-bottom: 2px solid transparent;
	color: var(--colour-ink-muted);
	font-weight: 700;
	padding: var(--space-2) var(--space-3);
	cursor: pointer;
}

.tabs button.active {
	color: var(--colour-ink);
	border-bottom-color: var(--colour-accent);
}

/* Profile tab chips — the mobile grammar: a coloured 36px icon chip
   per tab with a white glyph and a matching underline when active
   (blue challenges, GREEN pledges — the mobile pledges accent —
   violet relations). */

.tabs--chips {
	border-bottom: none;
	gap: var(--space-4);
}

.tabs--chips button.tab-chip {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--space-1);
	color: var(--colour-ink);
	font-weight: 700;
	font-size: 0.85rem;
	border-bottom: 3px solid transparent;
	padding: var(--space-2) var(--space-2) var(--space-2);
}

.tab-chip__icon {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 36px;
	height: 36px;
	border-radius: var(--radius-sm);
	color: #ffffff;
}

.tab-chip__icon svg {
	width: 22px;
	height: 22px;
}

.tab--blue .tab-chip__icon {
	background: var(--colour-info);
}

.tab--green .tab-chip__icon {
	background: var(--colour-impact);
	color: var(--colour-nav-bar);
}

.tab--yellow .tab-chip__icon {
	background: var(--colour-prize);
}

.tab--bronze .tab-chip__icon {
	background: var(--colour-rank-third);
}

/* The violet tab reads the chrome violet, not the heading ink: this
   is a fill under a white glyph, and heading ink lightens in the dark
   appearance where a fill under white content must not. */
.tab--violet .tab-chip__icon {
	background: var(--colour-nav-bar);
}

.tabs--chips button.tab--blue.active {
	border-bottom-color: var(--colour-info);
}

.tabs--chips button.tab--green.active {
	border-bottom-color: var(--colour-impact);
}

.tabs--chips button.tab--yellow.active {
	border-bottom-color: var(--colour-prize);
}

.tabs--chips button.tab--bronze.active {
	border-bottom-color: var(--colour-rank-third);
}

.tabs--chips button.tab--violet.active {
	border-bottom-color: var(--colour-nav-bar);
}

.pagination {
	display: flex;
	gap: var(--space-2);
	align-items: center;
	margin-top: var(--space-4);
}

/* The search box — the mobile search screen's rounded white field
   with a grey magnifier. */

.search-box {
	display: flex;
	align-items: center;
	gap: var(--space-2);
	flex: 1;
	background: var(--colour-page-sunken);
	border-radius: 8px;
	padding: var(--space-2) var(--space-3);
	color: var(--colour-ink-muted);
}

.search-box svg {
	width: 18px;
	height: 18px;
	flex-shrink: 0;
}

.search-box input {
	flex: 1;
	background: transparent;
	border: none;
	outline: none;
	padding: 0;
	font-weight: 600;
	color: var(--colour-ink);
}

.search-box input::placeholder {
	color: var(--colour-ink-muted);
	font-weight: 500;
}

/* The profile header — stats row under the identity, like the mobile
   profile's follower counts. */

.profile-stats {
	display: flex;
	gap: var(--space-8);
	margin-top: var(--space-3);
}

.profile-stat {
	display: flex;
	flex-direction: column;
	line-height: 1.2;
}

.profile-stat__value {
	font-weight: 700;
	font-size: 1.2rem;
	color: var(--colour-heading);
}

.profile-stat__label {
	font-size: 0.8rem;
	font-weight: 600;
	color: var(--colour-ink-muted);
}


.profile-header {
	background: var(--colour-page-header);
}

/* The profile header's "Support {name}" donation links. */

.profile-support {
	margin-top: var(--space-3);
}

.profile-support__links {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-3);
	list-style: none;
	margin: var(--space-1) 0 0;
	padding: 0;
}

/* The settings page's donation-link editor rows. */

.donation-link-row {
	margin-bottom: var(--space-2);
}

.donation-link-row .input {
	flex: 1;
	min-width: 8rem;
}

/* Gradient cards — the mobile organisation page: white-on-gradient,
   centred. */

.card--gradient {
	background: var(--gradient-brand-blue);
	border: none;
	color: #ffffff;
	text-align: center;
}

.card--gradient .page-title {
	color: #ffffff;
}

.card--gradient .muted {
	color: rgb(255 255 255 / 75%);
}

/* ORGANISATION PAGE — the award-style profile (design handoff):
   standard brand-blue hero, white overlapping stats card, gold-ringed
   featured-challenge card, and recent pledges. The hero and cards
   deliberately commit to the branded look in both themes;
   the pledge rows follow the page surface. */

.org-hero {
	margin: calc(-1 * var(--space-6)) calc(-1 * var(--space-4)) 0;
	padding: var(--space-8) var(--space-4) calc(var(--space-8) + var(--space-6));
	background: var(--gradient-brand-blue);
	color: #ffffff;
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
}

.org-hero .avatar {
	width: 112px;
	height: 112px;
	background: #ffffff;
	box-shadow: 0 0 0 4px #ffffff, 0 10px 15px rgb(0 0 0 / 20%);
}

.org-hero .avatar--fallback {
	font-size: 2.5rem;
}

.org-hero__name {
	margin: var(--space-4) 0 0;
	font-size: 1.875rem;
	font-weight: 800;
	color: #ffffff;
}

.org-hero__handle {
	margin: var(--space-1) 0 0;
	color: rgb(255 255 255 / 80%);
}

.org-hero__description {
	margin: var(--space-4) 0 0;
	max-width: 20rem;
	line-height: 1.6;
	color: rgb(255 255 255 / 95%);
}

.org-hero__website {
	margin-top: var(--space-3);
	color: #ffffff;
	text-decoration: underline;
}

.org-hero__actions {
	margin-top: var(--space-6);
	display: flex;
	align-items: center;
	gap: var(--space-3);
}

/* The Follow button inherits the hero's magenta pill look without
   changing the shared FollowButton component. */

.org-hero__actions .btn {
	border: none;
	border-radius: 999px;
	padding: var(--space-3) var(--space-6);
	font-size: 1rem;
	font-weight: 700;
	background: var(--colour-award-action);
	color: #ffffff;
	box-shadow: 0 10px 15px rgb(0 0 0 / 20%);
}

.pill {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	border: none;
	border-radius: 999px;
	padding: var(--space-3) var(--space-6);
	font-size: 1rem;
	font-weight: 700;
	cursor: pointer;
	text-decoration: none;
	box-shadow: 0 10px 15px rgb(0 0 0 / 20%);
}

.pill--gold {
	background: var(--colour-award-highlight);
	color: var(--colour-award-ink);
}

.pill--magenta {
	background: var(--colour-award-action);
	color: #ffffff;
}

.pill--sky {
	background: var(--colour-award-pill);
	color: #ffffff;
	padding: var(--space-2) var(--space-4);
	font-size: 0.875rem;
	box-shadow: none;
	flex-shrink: 0;
}

.pill--compact {
	padding: var(--space-2) var(--space-4);
	font-size: 0.875rem;
	box-shadow: 0 2px 3px rgb(0 0 0 / 20%);
}

/* The white stats card overlaps the hero's bottom edge. */

.org-stats-card {
	position: relative;
	margin: calc(-1 * var(--space-8)) auto 0;
	width: 100%;
	max-width: 26rem;
	background: #ffffff;
	border-radius: var(--radius-lg);
	padding: var(--space-4) var(--space-6);
	display: flex;
	justify-content: space-around;
	color: var(--colour-award-ink);
	box-shadow: var(--shadow-card);
}

.org-stat {
	display: flex;
	flex-direction: column;
	align-items: center;
}

.org-stat__value {
	font-size: 1.5rem;
	font-weight: 800;
}

.org-stat__label {
	font-size: 0.875rem;
}

.org-section {
	margin-top: var(--space-8);
}

.org-section__head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	margin-bottom: var(--space-3);
}

.org-section__title {
	margin: 0;
	font-size: 1.5rem;
	font-weight: 800;
}

.chip--live {
	text-transform: uppercase;
	letter-spacing: 0.05em;
	font-size: 0.75rem;
	font-weight: 700;
	padding: var(--space-1) var(--space-2);
	border-radius: var(--radius-sm);
	background: var(--colour-award-highlight);
	color: var(--colour-award-ink);
}

/* The featured-challenge card: gold ring, gradient top, white
   metrics bar. */

.featured-challenge {
	display: block;
	border-radius: var(--radius-lg);
	overflow: hidden;
	background: #ffffff;
	box-shadow: 0 0 0 4px rgb(243 186 37 / 60%), 0 25px 50px rgb(0 0 0 / 25%);
	text-decoration: none;
}

.featured-challenge__top {
	background: var(--gradient-org-featured);
	padding: var(--space-4);
	color: #ffffff;
}

.featured-challenge__brands {
	display: flex;
	align-items: center;
	gap: var(--space-2);
	width: fit-content;
	background: #ffffff;
	border-radius: var(--radius-md);
	padding: var(--space-2);
	color: var(--colour-award-ink);
}

.featured-challenge__wordmark {
	font-weight: 800;
	letter-spacing: 0.02em;
}

.featured-challenge__divider {
	width: 1px;
	height: 2rem;
	background: rgb(21 19 62 / 30%);
}

.featured-challenge__brands .avatar {
	width: 32px;
	height: 32px;
	box-shadow: none;
}

.featured-challenge__name {
	margin: var(--space-4) 0 0;
	font-size: 1.5rem;
	font-weight: 800;
	line-height: 1.2;
	color: #ffffff;
}

.featured-challenge__description {
	margin: var(--space-1) 0 0;
	font-size: 0.875rem;
	color: rgb(255 255 255 / 85%);
}

.featured-challenge__bar {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-3);
	padding: var(--space-4);
	background: #ffffff;
	color: var(--colour-award-ink);
}

.featured-challenge__stats {
	display: flex;
	gap: var(--space-4);
}

.featured-stat {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
}

.featured-stat__value {
	font-size: 1.125rem;
	font-weight: 800;
	line-height: 1;
}

.featured-stat__label {
	font-size: 0.6875rem;
	color: rgb(21 19 62 / 70%);
}

/* Recent pledge rows: thumbnail tile, clamped message, sky pill. */

.pledge-row {
	display: flex;
	align-items: center;
	gap: var(--space-3);
	background: var(--colour-page-raised);
	border-radius: var(--radius-md);
	padding: var(--space-3);
	box-shadow: var(--shadow-card);
}

.pledge-row + .pledge-row {
	margin-top: var(--space-3);
}

.pledge-row__tile {
	width: 56px;
	height: 56px;
	border-radius: var(--radius-sm);
	background: var(--gradient-org-tile);
	display: flex;
	align-items: center;
	justify-content: center;
	padding: var(--space-1);
	flex-shrink: 0;
	overflow: hidden;
}

.pledge-row__tile img {
	max-width: 100%;
	max-height: 40px;
	object-fit: contain;
}

.pledge-row__body {
	flex: 1;
	min-width: 0;
}

.pledge-row__title {
	font-size: 0.875rem;
	font-weight: 700;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.pledge-row__message {
	font-size: 0.75rem;
	color: var(--colour-ink-muted);
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}

/* Avatars — circular with the mobile white-ring style (the ring
   follows the surface colour in dark mode). The fallback disc is the
   mobile pattern: a brand-magenta fill when there is no image. */

.avatar {
	width: 40px;
	height: 40px;
	border-radius: 50%;
	object-fit: cover;
	background: var(--colour-page-sunken);
	box-shadow: 0 0 0 2px var(--colour-page), var(--shadow-card);
	flex-shrink: 0;
}

.avatar--sm {
	width: 36px;
	height: 36px;
}

.avatar--lg {
	width: 88px;
	height: 88px;
	box-shadow: 0 0 0 3px var(--colour-page), var(--shadow-card);
}

.avatar--fallback {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	background: var(--colour-accent);
	color: #ffffff;
	font-weight: 700;
	font-size: 1rem;
}

.avatar--fallback.avatar--lg {
	font-size: 2rem;
}

/* On dark chrome (the feed card's violet author bar, gradient cards)
   the ring is always white, like the mobile app. */

.feed-card__author .avatar,
.card--gradient .avatar {
	box-shadow: 0 0 0 2px #ffffff, var(--shadow-card);
}

.card--gradient .avatar--lg {
	box-shadow: 0 0 0 3px #ffffff, var(--shadow-card);
}

.row {
	display: flex;
	gap: var(--space-3);
	align-items: center;
}

.row--between {
	justify-content: space-between;
}

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

.unread-dot {
	display: inline-block;
	width: 8px;
	height: 8px;
	border-radius: 50%;
	background: var(--colour-accent);
	margin-right: var(--space-2);
}

/* Responsive card grids — the trending feed's video-hero tiles and
   the challenge page's submissions list. Both flow to a single column
   on narrow viewports and multiple columns as space allows, instead
   of the original single-column stacks above. Appended rather than
   folded into `.feed-list`/`.tile-grid` so those stay exactly as they
   were for anything still using them. */

.feed-grid,
.submission-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
	gap: var(--space-4);
	align-items: start;
}

/* Grid pages want the full viewport: `.app-main`'s 860px reading
   width fits only two 280px columns, so pages containing a video
   grid relax the cap and let auto-fill do its job. */
.app-main:has(.feed-grid),
.app-main:has(.submission-grid) {
	max-width: 1440px;
}

/* `.card + .card` (defined above) adds a stacking margin that reads
   as an unwanted gap between grid rows — the grid's own `gap` already
   spaces submission cards out. */
.submission-grid > .card {
	margin-top: 0;
}

/* The video-hero feed tile: a tappable thumbnail with a play
   affordance, plus an author + title strip below — the video-feed
   anatomy the mobile app uses. Used when a trending entry's media is
   ready; `TrendingTile` falls back to the original `.feed-card` text
   treatment (above) otherwise. */

.video-tile {
	display: block;
	border-radius: var(--radius-md);
	overflow: hidden;
	box-shadow: var(--shadow-card);
	text-decoration: none;
	background: var(--colour-page-raised);
}

.video-tile:hover {
	filter: brightness(1.05);
}

.video-tile__thumb {
	position: relative;
	width: 100%;
	aspect-ratio: 9 / 16;
	background: var(--colour-nav-bar);
	overflow: hidden;
}

.video-tile__thumb img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.video-tile__play {
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	width: 52px;
	height: 52px;
	border-radius: 50%;
	display: flex;
	align-items: center;
	justify-content: center;
	background: rgb(23 23 23 / 45%);
	color: #ffffff;
	pointer-events: none;
}

.video-tile__play svg {
	width: 22px;
	height: 22px;
	margin-left: 2px; /* Optical centring of the play triangle. */
}

.video-tile__info {
	display: flex;
	align-items: center;
	gap: var(--space-2);
	padding: var(--space-3);
	background: var(--colour-nav-bar);
}

.video-tile__info .avatar {
	box-shadow: 0 0 0 2px #ffffff, var(--shadow-card);
}

.video-tile__text {
	display: flex;
	flex-direction: column;
	line-height: 1.3;
	min-width: 0;
}

.video-tile__username {
	color: #ffffff;
	font-weight: 700;
	font-size: 0.9rem;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.video-tile__title {
	color: rgb(255 255 255 / 75%);
	font-weight: 600;
	font-size: 0.8rem;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

@media (max-width: 480px) {
	.feed-grid,
	.submission-grid {
		grid-template-columns: 1fr;
	}
}
