/* =========================================================================
   promotoracultural.org — design system
   Built from the Promotora Cultural brand: the salmon/slate/blue/sand palette,
   the river-confluence isotype, and the paper-grain, ribbon-over-photograph
   composition language of their own graphic material.

   Everything colour-ish is a custom property so the five themes (paper /
   white / salmon / dark / night) can redefine it in one place. Components
   below the token block must never contain a raw hex.

   Two further axes sit beside the theme and compose freely with it:
   `data-shape` (pill vs soft corners) and `data-photo` (colour vs greyscale
   photography). Both are switched from the same appearance menu.
   ========================================================================= */

/* ---------------------------------------------------------------- fonts ---- */
@font-face {
	font-family: 'Figtree';
	font-style: normal;
	font-weight: 300 900;
	font-display: swap;
	src: url('../fonts/figtree-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: 'Figtree';
	font-style: normal;
	font-weight: 300 900;
	font-display: swap;
	src: url('../fonts/figtree-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;
}

/* Newsreader — the serif alternative offered in the appearance menu. Same two
   subsets and the same unicode ranges as Figtree above, so the pair swap
   cleanly. Variable across weight and optical size; only the roman is shipped,
   because nothing on this site is set in italic. Self-hosted like everything
   else — the site loads no font from a CDN. */
@font-face {
	font-family: 'Newsreader';
	font-style: normal;
	font-weight: 200 800;
	font-display: swap;
	src: url('../fonts/newsreader-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: 200 800;
	font-display: swap;
	src: url('../fonts/newsreader-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;
}

/* Instrument Serif — the third option: a display serif with a single weight,
   so the headings that ask for 800 simply get 400. That is the look, not a
   shortcoming; the size and the leading carry the emphasis instead. */
@font-face {
	font-family: 'Instrument Serif';
	font-style: normal;
	font-weight: 400;
	font-display: swap;
	src: url('../fonts/instrumentserif-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: 'Instrument Serif';
	font-style: normal;
	font-weight: 400;
	font-display: swap;
	src: url('../fonts/instrumentserif-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;
}

/* Prata — a high-contrast display serif, one weight. Google ships no latin-ext
   cut for it; `latin` already carries the accents these languages need, and
   anything beyond falls through the stack like every other script. */
@font-face {
	font-family: 'Prata';
	font-style: normal;
	font-weight: 400;
	font-display: swap;
	src: url('../fonts/prata-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;
}

/* EB Garamond — an old-style book serif, variable across weight. */
@font-face {
	font-family: 'EB Garamond';
	font-style: normal;
	font-weight: 400 800;
	font-display: swap;
	src: url('../fonts/ebgaramond-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: 'EB Garamond';
	font-style: normal;
	font-weight: 400 800;
	font-display: swap;
	src: url('../fonts/ebgaramond-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;
}

/* --------------------------------------------------------------- palette --- */
:root {
	/* brand families — the client's four colours with a tint/shade spectrum */
	--salmon-50:  #ffedea;
	--salmon-100: #fed6cf;
	--salmon-200: #faaea0;
	--salmon-300: #f18875;
	--salmon-400: #e8624a;
	--salmon-500: #e36a54;   /* client value — the primary */
	--salmon-600: #c94932;
	--salmon-700: #a63521;
	--salmon-800: #7f2a1a;
	--salmon-900: #531b11;

	--slate-50:  #f2f4f7;
	--slate-100: #e2e6ed;
	--slate-200: #c3cad7;
	--slate-300: #8f9aae;
	--slate-400: #586075;
	--slate-500: #47556f;
	--slate-600: #38445a;
	--slate-700: #2b3446;
	--slate-800: #1f2735;
	--slate-900: #141a25;

	/* The client's secondary. Deliberately not part of the ramp above: that
	   one carries --ink, --surface-3 and both dark themes, and re-centring
	   it here would have lifted --slate-900 out of the dark. */
	--slate-brand: #5d7497;   /* client value — the secondary */

	--blue-50:  #f0f5f9;
	--blue-100: #dde8f1;
	--blue-200: #bcd2e3;
	--blue-300: #81aaca;     /* client value */
	--blue-400: #7791b3;
	--blue-500: #667b9a;     /* client value */
	--blue-600: #53627d;
	--blue-700: #3f4d64;

	--sand-50:  #fefaf1;
	--sand-100: #fdf2dd;
	--sand-200: #f9e2b6;
	--sand-300: #f5c77a;     /* client value */
	--sand-400: #f4cb7b;     /* client value */
	--sand-500: #e8ac4d;
	--sand-600: #c78a2f;

	/* type + shape, theme-independent.
	   Figtree is subset to latin and latin-ext, so the eleven languages the
	   site ships in do not all fit in it. Font fallback is per glyph, which
	   means Latin copy still renders in Figtree while Japanese, Korean,
	   Chinese, Cyrillic and Devanagari fall through to the reader's own system
	   faces — named here rather than left to chance, because the default for a
	   missing script is usually the ugliest face installed. */
	--stack-sans: 'Figtree', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
		Helvetica, Arial,
		'Yu Gothic UI', 'Hiragino Sans', Meiryo,                  /* ja */
		'Malgun Gothic', 'Apple SD Gothic Neo',                   /* ko */
		'Microsoft YaHei', 'PingFang SC', 'Noto Sans CJK SC',     /* zh */
		'Nirmala UI', 'Noto Sans Devanagari',                     /* hi */
		sans-serif;
	/* the serif alternative, with the same eleven-language fallback chain —
	   in the serif faces this time, so a Japanese or Russian reader who picks
	   it sees a serif too instead of dropping back to the sans */
	/* Every serif option ends in the same chain, so the four of them are the
	   face plus this — a Japanese or Russian reader who picks any of them gets
	   a serif too, instead of dropping back to the sans. */
	--serif-tail: Georgia, 'Times New Roman',
		'Yu Mincho', 'Hiragino Mincho ProN',                      /* ja */
		'Nanum Myeongjo', 'Apple SD Gothic Neo',                  /* ko */
		'Songti SC', SimSun, 'Noto Serif CJK SC',                 /* zh */
		'Noto Serif Devanagari', Kokila,                          /* hi */
		serif;
	--stack-serif:      'Newsreader',       var(--serif-tail);
	--stack-instrument: 'Instrument Serif', var(--serif-tail);
	--stack-prata:      'Prata',            var(--serif-tail);
	--stack-garamond:   'EB Garamond',      var(--serif-tail);
	--sans: var(--stack-sans);
	/* --surface-3 is a dark colour in every theme, so what sits on it is
	   always light — this is not a per-theme decision */
	--on-dark:    #ffffff;
	--radius:     18px;
	--radius-sm:  12px;
	--radius-lg:  28px;
	/* Photographs round on their own axis: a client may want square pictures
	   inside rounded panels, or the reverse. Its own value, deliberately, not
	   var(--radius) — deriving it meant squaring the cards squared the
	   photographs too, and the two axes stopped being independent. */
	--radius-img: 18px;
	--wrap:       1200px;
	--wrap-narrow: 780px;
	--ease:       cubic-bezier(.22,.61,.36,1);

	/* paper grain — a single inline turbulence tile, reused by every theme */
	--grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='.55'/%3E%3C/svg%3E");
}

/* ------------------------------------------------------------ theme: light - */
:root,
[data-theme='light'] {
	--bg:          #faf6f2;
	--bg-2:        #f3ece6;
	--surface:     #ffffff;
	--surface-2:   #f6f1ec;
	--surface-3:   var(--slate-800);
	--ink:         #2b3446;
	--ink-2:       var(--slate-500);
	--muted:       #7d879b;
	--line:        #e7ded6;
	--line-strong: #d5c9bf;

	--brand:        var(--salmon-500);
	--brand-strong: var(--salmon-600);
	--brand-soft:   var(--salmon-50);
	--on-brand:     #ffffff;
	--brand-2:      var(--slate-brand);
	--accent:       var(--sand-400);
	--accent-ink:   var(--sand-600);

	/* The veil the menu bar wears when it floats over moving imagery, and
	   the ink that goes on it. Every theme puts white on a dark veil,
	   because the hero is white-on-photograph in every theme. */
	--media-veil:   #0b1220;
	--on-media:     #ffffff;

	/* Copies of the theme's own colours, taken here where nothing has shadowed
	   them yet. The see-through header redefines --ink and friends on itself so
	   its children follow with no extra rules — but its dropdown panels are
	   solid, not see-through, and need the theme back. These let them ask for
	   it. They resolve per theme, because substitution happens on :root. */
	--ink-root:        var(--ink);
	--ink-2-root:      var(--ink-2);
	--surface-root:    var(--surface);
	--surface-2-root:  var(--surface-2);
	--line-root:       var(--line);
	--brand-soft-root: var(--brand-soft);
	--blue:         var(--blue-500);
	--blue-soft:    var(--blue-50);

	--scrim:      linear-gradient(180deg, rgba(20,26,37,.62) 0%, rgba(20,26,37,.30) 45%, rgba(20,26,37,.76) 100%);
	--shadow:     0 22px 50px -26px rgba(31,39,53,.42);
	--shadow-sm:  0 8px 22px -14px rgba(31,39,53,.40);
	--grain-op:   .028;
	color-scheme: light;
}

/* ------------------------------------------------------------ theme: white -
   Slate and blue lead; salmon steps back to a secondary role. */
[data-theme='white'] {
	--bg:          #ffffff;
	--bg-2:        #f2f5f9;
	--surface:     #ffffff;
	--surface-2:   #eef2f7;
	--surface-3:   var(--slate-700);
	--ink:         #1b2230;
	--ink-2:       var(--slate-500);
	--muted:       #78839a;
	--line:        #e3e8f0;
	--line-strong: #ccd4e1;

	--brand:        var(--slate-500);
	--brand-strong: var(--slate-600);
	--brand-soft:   var(--slate-50);
	--on-brand:     #ffffff;
	--brand-2:      var(--salmon-500);
	--accent:       var(--blue-300);
	--accent-ink:   var(--blue-600);
	--blue:         var(--blue-500);
	--blue-soft:    var(--blue-50);

	--scrim:      linear-gradient(180deg, rgba(20,26,37,.62) 0%, rgba(20,26,37,.30) 45%, rgba(20,26,37,.78) 100%);
	--shadow:     0 22px 50px -26px rgba(27,34,48,.30);
	--shadow-sm:  0 8px 22px -14px rgba(27,34,48,.28);
	--grain-op:   .016;
	color-scheme: light;
}

/* ------------------------------------------------------------- theme: dark - */
[data-theme='dark'] {
	--bg:          #141a25;
	--bg-2:        #10151e;
	--surface:     #1d2532;
	--surface-2:   #253041;
	--surface-3:   #0d121a;
	--ink:         #eef1f6;
	--ink-2:       #c3ccdb;
	--muted:       #8b96ab;
	--line:        rgba(255,255,255,.10);
	--line-strong: rgba(255,255,255,.20);

	--brand:        var(--salmon-300);
	--brand-strong: var(--salmon-200);
	--brand-soft:   rgba(228,154,130,.14);
	--on-brand:     #21160f;
	--brand-2:      var(--blue-300);
	--accent:       var(--sand-300);
	--accent-ink:   var(--sand-200);
	--blue:         var(--blue-300);
	--blue-soft:    rgba(129,170,202,.12);

	--scrim:      linear-gradient(180deg, rgba(8,11,16,.60) 0%, rgba(8,11,16,.34) 45%, rgba(8,11,16,.86) 100%);
	--shadow:     0 24px 56px -28px rgba(0,0,0,.75);
	--shadow-sm:  0 10px 26px -16px rgba(0,0,0,.7);
	--grain-op:   .05;
	color-scheme: dark;
}

/* ------------------------------------------------------------ theme: night -
   Deeper than dark, and led by the blue rather than the salmon. */
[data-theme='night'] {
	--bg:          #0a0e15;
	--bg-2:        #060910;
	--surface:     #121924;
	--surface-2:   #1a2331;
	--surface-3:   #04070c;
	--ink:         #e9eff8;
	--ink-2:       #b6c2d6;
	--muted:       #7c8aa2;
	--line:        rgba(255,255,255,.09);
	--line-strong: rgba(255,255,255,.18);

	--brand:        var(--blue-300);
	--brand-strong: #a6c7de;
	--brand-soft:   rgba(129,170,202,.16);
	--on-brand:     #061019;
	--brand-2:      var(--salmon-300);
	--accent:       var(--blue-200);
	--accent-ink:   var(--blue-200);
	--blue:         var(--blue-300);
	--blue-soft:    rgba(129,170,202,.12);

	--scrim:      linear-gradient(180deg, rgba(4,7,12,.66) 0%, rgba(4,7,12,.38) 45%, rgba(4,7,12,.90) 100%);
	--shadow:     0 26px 60px -28px rgba(0,0,0,.85);
	--shadow-sm:  0 10px 28px -16px rgba(0,0,0,.8);
	--grain-op:   .055;
	color-scheme: dark;
}

/* ----------------------------------------------------------- theme: salmon -
   Reworked for contrast: whiter surfaces, much darker ink, a deeper brand. */
[data-theme='salmon'] {
	--bg:          #fff3ec;
	--bg-2:        #fbdfd2;
	--surface:     #ffffff;
	--surface-2:   #fdeee6;
	--surface-3:   #2f150d;
	--ink:         #2b1109;
	--ink-2:       #592e20;
	--muted:       #8a5a48;
	--line:        #f4d9cb;
	--line-strong: #dda78e;

	--brand:        var(--salmon-700);
	--brand-strong: var(--salmon-800);
	--brand-soft:   #fde3d8;
	--on-brand:     #ffffff;
	--brand-2:      var(--slate-600);
	--accent:       var(--sand-500);
	--accent-ink:   #a06a1c;
	--blue:         var(--slate-600);
	--blue-soft:    #f2e5de;

	--scrim:      linear-gradient(180deg, rgba(47,21,13,.64) 0%, rgba(47,21,13,.30) 45%, rgba(47,21,13,.86) 100%);
	--shadow:     0 22px 50px -26px rgba(75,30,16,.46);
	--shadow-sm:  0 8px 22px -14px rgba(75,30,16,.42);
	--grain-op:   .038;
	color-scheme: light;
}

/* ------------------------------------------------------------- cta band ----
   The closing band of Inicio, Nosotros and Aliados. It rests in the light blue
   the brand already uses and turns to the salmon gradient while the pointer is
   on it — asked for on 2026-08-18, and asked for twice, because on the page it
   reads as two different blocks.

   Written as tokens rather than as colours in the component (house rule 3), and
   after the theme blocks on purpose: `:root` and `[data-theme='…']` have the
   same specificity, so the dark pair below is what a dark page ends up with.
   The hover gradient is the same in every theme — it is the brand orange, not
   a shade of the page. */
:root,
[data-theme='light'],
[data-theme='white'],
[data-theme='salmon'] {
	--cta-bg:  var(--blue-100);
	--cta-ink: var(--ink);
}
[data-theme='dark'],
[data-theme='night'] {
	--cta-bg:  var(--blue-700);
	--cta-ink: #ffffff;
}

/* The two admission tones the palette did not already have: an open door and
   a sign-up sheet. Deeper on paper, lighter on a dark page, the same way the
   map ramp flips — a chip has to hold its contrast against both grounds. */
:root,
[data-theme='light'],
[data-theme='white'],
[data-theme='salmon'] {
	--go:  #1c7a52;
	--reg: #5b4bbd;
}
[data-theme='dark'],
[data-theme='night'] {
	--go:  #59c495;
	--reg: #a89bf0;
}
:root {
	--cta-bg-hover:  linear-gradient(130deg, var(--salmon-600), var(--salmon-400) 55%, var(--sand-500));
	--cta-ink-hover: #ffffff;
}

/* ------------------------------------------------------------ the map -----
   The choropleth on the public dashboard. It needs a ramp of its own, because
   "more" does not read the same way on paper as on a dark page: on paper the
   busiest municipality is the darkest one, and on a dark page it has to be the
   brightest, or the map's own subject sinks into the background. A single ramp
   for both — which is what it had — left the dark themes drawing a dark blue
   on near-black, with a stroke the colour of the surface behind it. The
   municipalities with nothing to report are the ones this matters most for,
   since on a first visit that is the whole map.

   The home page's subregion map has never had the problem: it fills with one
   mid blue that shows up either way. */
:root,
[data-theme='light'],
[data-theme='white'],
[data-theme='salmon'] {
	/* Empty is a grey, not the palest blue: a municipality with nothing to
	   report has to be told apart from one with a single answer, and a ramp
	   whose first step is also its "no data" colour cannot do that. */
	--map-empty: #e3e5e9;
	--map-1: #cfe0ee;
	--map-2: var(--blue-200);
	--map-3: var(--blue-300);
	--map-4: var(--blue-500);
	--map-5: var(--blue-700);
	--map-line: rgba(255,255,255,.7);
}
[data-theme='dark'],
[data-theme='night'] {
	--map-empty: #3a4257;      /* slate, so "nothing here" is not read as "a little" */
	--map-1: #3f5b85;
	--map-2: #52759f;
	--map-3: #7099c0;
	--map-4: #a1c4dd;
	--map-5: #d9e8f4;
	--map-line: rgba(8,11,17,.55);
}

/* ---------------------------------------------------------- shape: corners -
   A second, theme-independent axis. `pill` is the fully-rounded original;
   `soft` keeps the rounding but stops short of a capsule. Anything that reads
   as a pill — buttons, chips, filters, the search bar — follows --pill so the
   two shapes never mix on one screen. */
:root, [data-shape='pill'] { --pill: 100px; --pill-sm: 100px; }
[data-shape='soft']        { --pill: 14px;  --pill-sm: 10px; }
[data-shape='square']      { --pill: 0;     --pill-sm: 0; }

/* --- card corners ---------------------------------------------------------
   `data-shape` is about pill-like controls; this is about the panels. Every
   card-like element already asks for --radius, so squaring them is one rule
   rather than a list of components. */
[data-card='card-sharp'] { --radius: 0; --radius-sm: 0; --radius-lg: 0; }

/* --- picture corners --- */
[data-pic='pic-sharp'] { --radius-img: 0; }

/* --- how wide a section heading may run -----------------------------------
   660px keeps a heading to a comfortable measure; full width suits a short
   title over a wide band. `none` rather than 100% so the centred variant
   still centres. */
:root                  { --head-w: none; }
[data-headw='narrow']  { --head-w: 660px; }

/* --- the numbered discs on the lines of work --- */
[data-num='hide'] .pillar-n { display: none; }

/* ------------------------------------------------- rule: section dividers -
   A line between one band and the next, on every page — the sections are all
   direct children of #nw-view, so one rule reaches them all. It hangs off the
   *following* section, which is why there is never a stray line under the last
   one. Where that following band is dark the borrowed --line would vanish, so
   those three get a light one instead. */
[data-rule='line'] #nw-view > section + section {
	border-top: 1px solid var(--line);
}
[data-rule='line'] #nw-view > section.band-dark,
[data-rule='line'] #nw-view > section.confluence,
[data-rule='line'] #nw-view > section.hero {
	border-top-color: rgba(255, 255, 255, .18);
}

/* ------------------------------------------------------- pad: button size -
   How much room a button takes. `normal` is what the site was built with;
   the two tighter steps are for seeing the page with a lighter touch. */
:root, [data-pad='normal'] { --btn-py: 14px; --btn-px: 26px; --btn-sm-py: 10px; --btn-sm-px: 18px; }
[data-pad='small']         { --btn-py: 10px; --btn-px: 20px; --btn-sm-py: 8px;  --btn-sm-px: 14px; }
[data-pad='xs']            { --btn-py: 6px;  --btn-px: 14px; --btn-sm-py: 5px;  --btn-sm-px: 11px; }

/* --------------------------------------------------- navcta: the seasons tab
   The seasons entry is a filled button among plain links, which is the point
   of it — but the client should be able to see the header without that
   emphasis, so `plain` dresses it exactly like its neighbours. */
[data-navcta='plain'] .nav-cta {
	background: transparent; color: var(--ink-2); box-shadow: none;
	border-color: transparent; margin-left: 0;
	padding: 9px 13px; font-weight: 600; font-size: .93rem;
}
[data-navcta='plain'] .nav-cta:hover { background: var(--surface-2); color: var(--ink); transform: none; }
[data-navcta='plain'] .nav-cta.active { background: var(--brand-soft); color: var(--brand); }
[data-navcta='plain'] .nav-cta svg { display: none; }

/* ---------------------------------------------------------- font: typeface -
   A fourth axis. The whole site runs off one family token, so swapping the
   stack is all it takes; the per-script fallbacks travel with each stack. */
[data-font='serif']      { --sans: var(--stack-serif); }
[data-font='instrument'] { --sans: var(--stack-instrument); }
[data-font='prata']      { --sans: var(--stack-prata); }
[data-font='garamond']   { --sans: var(--stack-garamond); }
/* Newsreader is a text face: at display sizes it wants less weight and none of
   the tight tracking the grotesque was given. */
[data-font='serif'] h1,
[data-font='serif'] h2,
[data-font='serif'] h3,
[data-font='serif'] h4 { font-weight: 600; letter-spacing: -.012em; }
[data-font='serif'] .eyebrow { letter-spacing: .14em; }
/* Instrument Serif ships one weight, so asking for 800 only synthesises a
   bolder face. Let the size do the work and give the headlines a little more
   room, which is how this face is meant to be set. */
[data-font='instrument'] h1,
[data-font='instrument'] h2,
[data-font='instrument'] h3,
[data-font='instrument'] h4 { font-weight: 400; letter-spacing: -.005em; line-height: 1.12; }
[data-font='instrument'] .eyebrow { font-weight: 400; letter-spacing: .2em; }
[data-font='instrument'] .btn,
[data-font='instrument'] .site-nav > a:not(.btn) { font-weight: 400; }
/* Prata is the same story — one weight, high contrast, and it needs air. */
[data-font='prata'] h1,
[data-font='prata'] h2,
[data-font='prata'] h3,
[data-font='prata'] h4 { font-weight: 400; letter-spacing: 0; line-height: 1.18; }
[data-font='prata'] .eyebrow { font-weight: 400; letter-spacing: .18em; }
[data-font='prata'] .btn,
[data-font='prata'] .site-nav > a:not(.btn) { font-weight: 400; }
/* EB Garamond has the weights but runs small and light for its size, so the
   headings keep some of their heft and the body text goes up a notch. */
[data-font='garamond'] h1,
[data-font='garamond'] h2,
[data-font='garamond'] h3,
[data-font='garamond'] h4 { font-weight: 600; letter-spacing: -.008em; }
[data-font='garamond'] body,
[data-font='garamond'] .lead { font-size: 1.05em; }
[data-font='garamond'] .eyebrow { letter-spacing: .15em; }

/* ------------------------------------------------------ border: button edge -
   A fifth axis. `full` is the original outline. `underline` strips the box
   entirely and lets a single rule appear under the control, and only while it
   is being pressed, focused or already active — the quietest possible border. */
[data-border='underline'] .btn {
	border-color: transparent; box-shadow: none; border-radius: 0;
}
[data-border='underline'] .btn:hover { transform: none; }
[data-border='underline'] .btn:active,
[data-border='underline'] .btn:focus-visible,
[data-border='underline'] .btn.active {
	border-bottom-color: currentColor;
}
[data-border='underline'] .site-nav > a:not(.btn) {
	border-radius: 0; border-bottom: 2px solid transparent; background: transparent;
}
[data-border='underline'] .site-nav > a:not(.btn):hover,
[data-border='underline'] .site-nav > a:not(.btn).active {
	background: transparent; border-bottom-color: currentColor;
}
[data-border='underline'] .tool-btn { border-color: transparent; border-radius: 0; }
[data-border='underline'] .tool-btn:hover { border-bottom-color: currentColor; }

/* -------------------------------------------------------- fill: button body -
   A sixth axis, after the outline buttons of manual.studio: no fill at all,
   just a hairline and the label, and the fill only arrives on hover. The two
   places buttons sit on a photograph or a colour wash — the hero and the CTA
   band — keep a white outline instead, or they would vanish. */
[data-fill='hollow'] .btn-primary,
[data-fill='hollow'] .btn-dark {
	background: transparent; color: var(--ink);
	border-color: var(--ink); box-shadow: none;
}
[data-fill='hollow'] .btn-primary:hover { background: var(--brand); color: var(--on-brand); border-color: var(--brand); }
[data-fill='hollow'] .btn-dark:hover    { background: var(--surface-3); color: var(--on-dark); border-color: var(--surface-3); }
[data-fill='hollow'] .hero .btn-primary,
[data-fill='hollow'] .band-dark .btn-primary {
	color: #fff; border-color: rgba(255,255,255,.65);
}
[data-fill='hollow'] .hero .btn-primary:hover,
[data-fill='hollow'] .band-dark .btn-primary:hover {
	background: rgba(255,255,255,.16); border-color: #fff; color: #fff;
}
[data-fill='hollow'] .chip { background: transparent; box-shadow: inset 0 0 0 1px currentColor; }

/* ------------------------------------------------------- photos: greyscale -
   A third axis: photographs sit in black and white until they are hovered.
   Only elements marked .photo are affected — never the logo or the ally
   marks, which are already monochrome by design. */
[data-photo='mono'] .photo {
	filter: grayscale(1) contrast(1.04);
	transition: filter .55s var(--ease);
}
[data-photo='mono'] .photo:hover,
[data-photo='mono'] .hero:hover .photo,
[data-photo='mono'] .purpose:hover .photo,
[data-photo='mono'] .pillar-flip:hover .photo,
[data-photo='mono'] .show-item:hover .photo,
[data-photo='mono'] .photo:focus-visible { filter: grayscale(0); }
/* A narrow screen is a screen with no pointer on it: there is nothing to hover
   with, so greyscale-until-hover would simply mean greyscale. The phone gets
   the photographs in colour. */
@media (max-width: 800px) {
	[data-photo='mono'] .photo { filter: none; }
}

/* ----------------------------------------------------------------- base ---- */
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }

body {
	margin: 0;
	background: var(--bg);
	color: var(--ink);
	font-family: var(--sans);
	font-size: 17px;
	line-height: 1.62;
	font-weight: 420;
	-webkit-font-smoothing: antialiased;
	overflow-x: hidden;
	transition: background-color .35s var(--ease), color .35s var(--ease);
}

/* the paper grain the client's posts always sit on */
body::before {
	content: '';
	position: fixed;
	inset: 0;
	background-image: var(--grain);
	opacity: var(--grain-op);
	pointer-events: none;
	z-index: 1;
	mix-blend-mode: multiply;
}
[data-theme='dark'] body::before { mix-blend-mode: screen; }

/* height:auto matters: several images carry width/height attributes for the
   aspect ratio and are then laid out at width:100%. Without it the attribute
   height wins and the picture is squashed. */
img { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-decoration: none; }
button { font: inherit; }

h1, h2, h3, h4 {
	font-weight: 800;
	line-height: 1.08;
	letter-spacing: -.022em;
	margin: 0 0 .45em;
}
h1 { font-size: clamp(2.5rem, 5.6vw, 4.3rem); }
h2 { font-size: clamp(1.9rem, 3.6vw, 2.9rem); }
h3 { font-size: 1.28rem; letter-spacing: -.012em; }
h4 { font-size: 1rem; }
p  { margin: 0 0 1rem; }

/* The type scale above is tuned for Latin. Two things have to give for the
   other scripts the site ships in: the headline tracking is negative, which
   crowds the square glyphs of Japanese, Korean and Chinese; and Devanagari
   hangs marks both above and below the line, so 1.08 is not enough leading
   for a heading. Matched on the lang attribute nw_mini sets. */
:is(:lang(ja), :lang(ko), :lang(zh)) :is(h1, h2, h3, h4) { letter-spacing: 0; }
:lang(hi) :is(h1, h2, h3, h4) { letter-spacing: 0; line-height: 1.32; }
:lang(hi) body, :lang(hi) .lead { line-height: 1.8; }

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

:focus-visible {
	outline: 3px solid var(--brand);
	outline-offset: 3px;
	border-radius: 4px;
}

/* every icon comes from the sprite in views/chrome/icons.html */
.ico { width: 1.05em; height: 1.05em; flex: none; }

.wrap { width: 100%; max-width: var(--wrap); margin: 0 auto; padding: 0 26px; }
.wrap-narrow { max-width: var(--wrap-narrow); }
/* A narrow measure that still starts where the wide column starts. On its own
   .wrap-narrow centres its 780px in the window, which left the opening of
   Nosotros and of Agenda about 200px to the right of every heading in the
   sections under them — the client's note of 2026-08-26, with a line drawn
   down the page to show it. The left margin here is the gutter the 1200px
   column has at this window width, so the two left edges meet whatever the
   width is and the measure keeps its length; under 1200px there is no gutter
   left to match and the max() falls back to the shared page padding. */
.wrap-narrow.wrap-flush {
	margin-inline: max(0px, calc((100% - var(--wrap)) / 2)) auto;
}

.skip-link {
	position: absolute; left: -999px; top: 0; z-index: 300;
	background: var(--ink); color: var(--bg);
	padding: 12px 18px; border-radius: 0 0 10px 0; font-weight: 700;
}
.skip-link:focus { left: 0; }

.eyebrow {
	font-weight: 800; text-transform: uppercase; letter-spacing: .18em;
	font-size: .72rem; color: var(--brand); margin: 0 0 14px;
}
.lead { font-size: 1.14rem; color: var(--ink-2); line-height: 1.6; }
.muted { color: var(--muted); }
.hl { color: var(--accent-ink); }
.hl-mark {
	background: linear-gradient(180deg, transparent 58%, var(--accent) 58%);
	padding: 0 .06em;
}

section { padding: 84px 0; position: relative; z-index: 2; }
.section-head { max-width: var(--head-w, 660px); margin-bottom: 46px; }
.section-head.center { margin-inline: auto; text-align: center; }
.section-head .lead { margin-bottom: 0; }

/* --------------------------------------------------------------- buttons --- */
.btn {
	display: inline-flex; align-items: center; gap: .55em; cursor: pointer;
	font-weight: 700; font-size: .97rem; letter-spacing: -.005em;
	padding: var(--btn-py) var(--btn-px); border-radius: var(--pill); border: 1.5px solid transparent;
	transition: transform .16s var(--ease), box-shadow .2s, background .2s,
		color .2s, border-color .2s;
	white-space: nowrap;
}
.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0); }
.btn svg { width: 1.05em; height: 1.05em; }

.btn-primary { background: var(--brand); color: var(--on-brand); box-shadow: var(--shadow-sm); }
.btn-primary:hover { background: var(--brand-strong); }
.btn-ghost { border-color: var(--line-strong); color: var(--ink); background: transparent; }
.btn-ghost:hover { border-color: var(--ink); background: var(--surface); }
.btn-on-photo { border-color: rgba(255,255,255,.5); color: #fff; background: rgba(255,255,255,.08); backdrop-filter: blur(6px); }
.btn-on-photo:hover { background: rgba(255,255,255,.18); border-color: #fff; }
.btn-dark { background: var(--surface-3); color: var(--on-dark); }
.btn-sm { padding: var(--btn-sm-py) var(--btn-sm-px); font-size: .89rem; }

/* ------------------------------------------------------------ brand marks -- */
/* One SVG per mark, recoloured by CSS masks so it follows the active theme. */
.mark {
	display: block;
	background-color: currentColor;
	-webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
	-webkit-mask-position: center; mask-position: center;
	-webkit-mask-size: contain; mask-size: contain;
}
.mark-iso {
	-webkit-mask-image: url('../brand/svg/isotype.svg');
	mask-image: url('../brand/svg/isotype.svg');
	aspect-ratio: 209 / 213;
}
.mark-logo {
	-webkit-mask-image: url('../brand/svg/logo.svg');
	mask-image: url('../brand/svg/logo.svg');
	aspect-ratio: 1498 / 402;
}
@supports not ((-webkit-mask-image: url('#')) or (mask-image: url('#'))) {
	.mark-iso  { background: url('../brand/svg/isotype-salmon.svg') center/contain no-repeat; }
	.mark-logo { background: url('../brand/svg/logo-salmon.svg') center/contain no-repeat; }
}

.brand { display: inline-flex; align-items: center; gap: 13px; }
/* The header carries the wordmark only — the isotype is the M inside it, so
   showing both said the same thing twice. It therefore has to keep working all
   the way down to a phone, where it used to be dropped in favour of the
   isotype; it shrinks instead. */
/* Width is a base times a scale, rather than one number, so the size axis and
   the responsive step-down compose instead of overwriting each other: the
   breakpoints move --logo-w, the axis moves --logo-scale. */
.brand .mark-logo {
	width: calc(var(--logo-w, 150px) * var(--logo-scale, 1));
	color: var(--logo-ink, var(--ink));
}

/* --- logo colour ------------------------------------------------------------
   `ink` is the default and deliberately has no rule: it falls through to
   var(--ink), which is what lets it follow the header over moving imagery. */
:root[data-logo-color="coral"] .brand .mark-logo { --logo-ink: var(--brand); }
:root[data-logo-color="sand"]  .brand .mark-logo { --logo-ink: var(--accent-ink); }
:root[data-logo-color="slate"] .brand .mark-logo { --logo-ink: var(--brand-2); }

/* --- logo size --- */
:root[data-logo-size="sm"] { --logo-scale: .76; }
:root[data-logo-size="md"] { --logo-scale: 1; }
:root[data-logo-size="lg"] { --logo-scale: 1.28; }
.brand-stack { display: flex; flex-direction: column; gap: 3px; }
.brand-stack small {
	font-size: .64rem; letter-spacing: .21em; text-transform: uppercase;
	color: var(--muted); font-weight: 700;
}

/* ------------------------------------------------------------- social ----
   Deliberately quiet: the marks sit at low opacity and in the surrounding ink
   until pointed at, when each takes its own colour. The rail is fixed under
   the menu bar and steps out of the way on a phone, where the footer row is
   the one that carries them. */
.social-rail {
	position: fixed; top: calc(78px + 14px); right: 18px; z-index: 90;
	display: flex; flex-direction: column; gap: 6px;
}
.social-link {
	display: grid; place-items: center; width: 36px; height: 36px;
	border-radius: var(--pill); color: var(--ink-2); opacity: .62;
	/* a faint disc under each, so the mark reads against photography as well
	   as against paper without becoming loud */
	background: color-mix(in srgb, var(--ink) 9%, transparent);
	backdrop-filter: blur(6px);
	transition: opacity .2s, color .2s, background .2s, transform .2s;
}
.social-link svg { width: 19px; height: 19px; }
.social-link:hover, .social-link:focus-visible {
	opacity: 1; transform: translateY(-1px);
	background: color-mix(in srgb, currentColor 12%, transparent);
}
.social-link:nth-child(1):hover { color: #d62976; }
.social-link:nth-child(2):hover { color: #ff0000; }
.social-link:nth-child(3):hover { color: #25d366; }
/* over the hero the rail is on photography, so it needs the lighter ink */
:root.has-immersive .social-rail .social-link {
	color: var(--on-media); opacity: .7;
	background: color-mix(in srgb, var(--media-veil) 34%, transparent);
}

.social-row { display: flex; gap: 4px; margin-top: 16px; }

/* ------------------------------------------------------- section rail ----
   The other side of the window from the social links, so the two never meet.
   Quiet like them until pointed at; the section being read is marked without
   needing a hover. */
.jump-rail {
	position: fixed; left: 16px; top: 50%; transform: translateY(-50%);
	z-index: 88; display: flex; flex-direction: column; gap: 5px;
}
.jump-dot {
	display: grid; place-items: center; width: 32px; height: 32px;
	border: 0; padding: 0; cursor: pointer;
	border-radius: var(--pill); color: var(--ink-2); opacity: .5;
	background: color-mix(in srgb, var(--ink) 8%, transparent);
	backdrop-filter: blur(6px);
	transition: opacity .2s, color .2s, background .2s, transform .2s;
}
.jump-dot svg { width: 15px; height: 15px; }
.jump-dot:hover, .jump-dot:focus-visible {
	opacity: 1; color: var(--brand); transform: translateX(2px);
	background: color-mix(in srgb, var(--brand) 14%, transparent);
}
.jump-dot.on {
	opacity: 1; color: var(--on-brand); background: var(--brand);
}
/* over the hero it is on photography, like the social rail */
:root.has-immersive .jump-dot { color: var(--on-media); }

@media (max-width: 1180px) {
	.jump-rail { display: none; }
}
/* The footer styles its links as list rows — block, with vertical padding —
   and that beat the disc's own centring on specificity, leaving each glyph in
   the top-left corner of its circle. These are buttons, not rows. */
.site-footer .social-link {
	display: grid; place-items: center;
	width: 36px; height: 36px; padding: 0; flex: none;
	color: #fff; opacity: .72;
	background: rgba(255,255,255,.12);
}
.social-link svg { display: block; }
.site-footer .social-link:hover { background: rgba(255,255,255,.22); }

/* One turn a second, then three seconds still — 25% of a four-second cycle is
   the flip, the rest is the rest. */
@keyframes nusoftTurn {
	0%   { transform: rotateY(0deg); }
	25%  { transform: rotateY(360deg); }
	100% { transform: rotateY(360deg); }
}
.footer-by img {
	animation: nusoftTurn 4s var(--ease) infinite;
	transform-style: preserve-3d;
}
[data-anim='still'] .footer-by img { animation: none; }
@media (prefers-reduced-motion: reduce) {
	.footer-by img { animation: none; }
}

@media (max-width: 960px) {
	.social-rail { display: none; }
}

/* ---------------------------------------------------------------- header --- */
.site-header {
	position: sticky; top: 0; z-index: 100;
	background: color-mix(in srgb, var(--bg) 82%, transparent);
	backdrop-filter: saturate(1.5) blur(14px);
	border-bottom: 1px solid transparent;
	transition: border-color .3s, box-shadow .3s, background .3s;
}
.site-header.scrolled {
	border-color: var(--line);
	box-shadow: 0 10px 30px -26px rgba(0,0,0,.7);
}

/* --- imagery behind the menu bar --------------------------------------------
   Sticky reserves its own height at the top of the flow; fixed does not. That
   single change is the whole effect: the hero now starts at y=0 and its
   existing top padding (140px, and 132px on Nosotros) already clears the 78px
   bar, so nothing has to be pulled up or padded out. Everything below behaves
   exactly as before, because a sticky header pinned at top:0 and a fixed one
   occupy the same place once the page has scrolled at all. */
:root.has-immersive .site-header { position: fixed; left: 0; right: 0; top: 0; }

/* Almost transparent, so the film or the photographs read through. The ink is
   redefined rather than each child restyled — the wordmark, the links and the
   tool buttons all resolve their colours from these, so they follow with no
   further rules. It is white on a dark veil in every theme because the hero
   itself is white-on-photograph in every theme; --media-veil is the one place
   to change that. Placed after .scrolled so it wins on equal specificity. */
.site-header.over-media {
	background: color-mix(in srgb, var(--media-veil) 34%, transparent);
	border-bottom-color: transparent;
	box-shadow: none;
	--ink:        var(--on-media);
	--ink-2:      color-mix(in srgb, var(--on-media) 80%, transparent);
	--surface:    color-mix(in srgb, var(--on-media) 14%, transparent);
	--surface-2:  color-mix(in srgb, var(--on-media) 22%, transparent);
	--brand-soft: color-mix(in srgb, var(--on-media) 20%, transparent);
	--line:       color-mix(in srgb, var(--on-media) 34%, transparent);
}
.site-header.over-media .site-nav > a:not(.btn).active { color: var(--on-media); }
.site-header.over-media .tool-btn { backdrop-filter: blur(8px); }

/* The dropdowns are solid panels that happen to hang off a see-through bar, so
   they take the theme's colours back rather than inheriting the header's. */
.site-header.over-media .tool-menu {
	--ink:        var(--ink-root);
	--ink-2:      var(--ink-2-root);
	--surface:    var(--surface-root);
	--surface-2:  var(--surface-2-root);
	--brand-soft: var(--brand-soft-root);
	--line:       var(--line-root);
	color: var(--ink-root);
}
.header-inner {
	display: flex; align-items: center; justify-content: space-between;
	height: 78px; gap: 18px;
}
.site-nav { display: flex; align-items: center; gap: 2px; }
/* Two-word labels — "Open calls", "Datos abiertos", "Informes de gestión" —
   were breaking across two lines as soon as the row got tight, which made the
   bar taller than the header. They keep their line; if the row runs out of
   width the drawer takes over at 1240px. */
.site-nav > a { white-space: nowrap; }
.site-nav > a:not(.btn) {
	padding: 9px 13px; border-radius: var(--pill); font-weight: 600;
	font-size: .93rem; color: var(--ink-2);
	transition: color .2s, background .2s;
}
.site-nav > a:not(.btn):hover { color: var(--ink); background: var(--surface-2); }
.site-nav > a:not(.btn).active { color: var(--brand); background: var(--brand-soft); }
.nav-cta { margin-left: 6px; }

.header-tools { display: flex; align-items: center; gap: 8px; }

.nav-toggle {
	display: none; flex-direction: column; justify-content: center; gap: 5px;
	width: 44px; height: 44px; border: 0; background: transparent;
	cursor: pointer; padding: 10px;
}
.nav-toggle span {
	height: 2.5px; background: var(--ink); border-radius: 2px;
	transition: transform .28s var(--ease), opacity .2s;
}
.nav-toggle[aria-expanded='true'] span:nth-child(1) { transform: translateY(7.5px) rotate(45deg); }
.nav-toggle[aria-expanded='true'] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded='true'] span:nth-child(3) { transform: translateY(-7.5px) rotate(-45deg); }

/* theme + language controls */
.tool-btn {
	display: inline-flex; align-items: center; justify-content: center; gap: 6px;
	height: 40px; min-width: 40px; padding: 0 12px;
	border: 1.5px solid var(--line); border-radius: var(--pill);
	background: var(--surface); color: var(--ink-2); cursor: pointer;
	font-size: .85rem; font-weight: 700;
	transition: border-color .2s, color .2s, background .2s;
}
.tool-btn:hover { border-color: var(--line-strong); color: var(--ink); }
.tool-btn svg { width: 18px; height: 18px; }

.tool { position: relative; }
.tool-menu {
	position: absolute; right: 0; top: calc(100% + 8px); z-index: 120;
	min-width: 168px; padding: 7px;
	background: var(--surface); border: 1px solid var(--line);
	border-radius: 14px; box-shadow: var(--shadow);
	display: none; flex-direction: column; gap: 2px;
	/* eleven languages no longer fit on a short screen */
	max-height: min(70vh, 480px); overflow-y: auto;
}
.tool-menu[data-open='1'] { display: flex; }
/* While the portal panel is open the page behind it softens, so the note is
   the only thing in focus. The blur is on the page's own blocks rather than on
   a veil above them: the panel hangs off the header, and a veil covering
   everything would have had to blur the very bar it belongs to. Nothing under
   it can be clicked — the click closes the panel instead, through the document
   handler that already watches for one outside a tool. */
:root.has-portal #nw-view,
:root.has-portal #nw-footer,
:root.has-portal #nw-social,
:root.has-portal #nw-jump {
	filter: blur(5px) saturate(.85); pointer-events: none; user-select: none;
}
#nw-view, #nw-footer, #nw-social, #nw-jump { transition: filter .25s var(--ease); }
@media (prefers-reduced-motion: reduce) {
	#nw-view, #nw-footer, #nw-social, #nw-jump { transition: none; }
}

/* A panel that says something rather than offering a list of choices — the
   portal note. Same shell as the menus, ordinary prose inside. */
.tool-note { width: 300px; padding: 18px 18px 16px; gap: 10px; }
.tool-note-t { font-weight: 800; color: var(--ink); margin: 0; }
.tool-note-d { font-size: .88rem; line-height: 1.55; color: var(--ink-2); margin: 0; }
.tool-note .btn { align-self: flex-start; }
/* The staff way in, under the button the public uses. Quiet on purpose — a
   link the size of the note's own small print, not a second call to action. */
.tool-note-admin {
	align-self: flex-start; margin-top: -2px;
	font-size: .82rem; color: var(--muted); text-decoration: underline;
	text-underline-offset: .18em; text-decoration-thickness: 1px;
	text-decoration-color: color-mix(in srgb, var(--muted) 40%, transparent);
	transition: color .2s var(--ease);
}
.tool-note-admin:hover { color: var(--brand); text-decoration-color: currentColor; }
.tool-note-admin:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 2px; }

/* On a narrow screen a panel cannot hang off its own button: 300px anchored to
   the right edge of a button that is itself near the right edge simply runs off
   the left of the window, which is what the portal note was doing. Under 620px
   every tool panel becomes a sheet pinned under the bar — the language list and
   the appearance menu included, since eleven languages had the same problem in
   a narrower way.

   `fixed` resolves against the header here rather than the window, because the
   bar carries a backdrop-filter and that makes it the containing block. It
   comes to the same thing: the header is the full width of the window and sits
   at the top of it. */
@media (max-width: 620px) {
	.tool-menu {
		position: fixed; top: 86px; left: 12px; right: 12px;
		width: auto; min-width: 0; max-height: calc(100vh - 120px);
	}
	.tool-note { width: auto; }
}
.tool-menu button {
	display: flex; align-items: center; gap: 10px; width: 100%;
	padding: 9px 12px; border: 0; border-radius: 9px; cursor: pointer;
	background: transparent; color: var(--ink-2);
	font-size: .9rem; font-weight: 600; text-align: left;
}
.tool-menu button:hover { background: var(--surface-2); color: var(--ink); }
/* The chosen option has to be unmistakable at a glance — with ten axes open at
   once, a faint tint was not enough. It gets the brand colour, a heavier
   label, a rule down its leading edge and a tick at the end. */
.tool-menu button { position: relative; }
.tool-menu button[aria-checked='true'] {
	color: var(--brand); background: var(--brand-soft); font-weight: 700;
	box-shadow: inset 2px 0 0 var(--brand);
}
.tool-menu button[aria-checked='true']::after {
	content: '✓';
	margin-left: auto; padding-left: 8px;
	font-size: .95em; line-height: 1; font-weight: 700;
}
/* (the language rows already push their code right with margin-left:auto
   further down, so the tick simply follows it)

   The appearance menu carries eleven groups now, which is far too tall for one
   column. Each group is a .tool-block, and the menu lays them out in columns —
   three where there is room, two on a laptop, one on a phone. */
/* Columns rather than a grid: a grid aligns rows, so a five-option axis beside
   a two-option one leaves a hole under the short one. Multi-column packs each
   block against the previous, and break-inside keeps a heading with its
   options. The menu is tall enough here that the balanced columns fit without
   scrolling; below that it falls back to one column and scrolls as before. */
/* Ten axes no longer fit in one column, so the menu lays them out in columns —
   three where there is room, two on a laptop, one on a phone.

   A grid rather than CSS columns or flex column-wrap: both of those pack more
   tightly, but both overflow sideways the moment a height is imposed on them,
   and a menu that scrolls horizontally is worse than one with some whitespace.
   The grid aligns rows, so the five-option theme leaves a little air beneath
   its shorter neighbours; that is the trade. */
/* Twenty-two axes and counting, so this earns more room than it used to: a
   column per axis-and-a-bit rather than the two it started with. The count is
   the reason it steps up by viewport rather than staying fixed — at every width
   it takes as many columns as fit without the panel running off screen, and
   max-width keeps it on screen whatever it asks for. */
.tool-menu-wide {
	min-width: 210px;
	display: none;
	grid-template-columns: repeat(2, minmax(164px, 1fr));
	align-content: start; align-items: start;
	gap: 2px 14px; padding: 12px;
	/* The panel hangs off the tool button, so `right: 0` is the button's right
	   edge, not the window's — and a width chosen for the window pushed its
	   left edge off screen. The button sits at the right edge of the header
	   .wrap, so the room to its left is half the window plus half the wrap;
	   this is that, less a gutter. */
	max-width: calc((100vw + var(--wrap)) / 2 - 46px);
	/* taller than the language menu: laid out in columns it earns the room */
	max-height: min(88vh, 660px);
}
.tool-menu-wide[data-open='1'] { display: grid; }
@media (min-width: 900px) {
	.tool-menu-wide { grid-template-columns: repeat(3, minmax(150px, 1fr)); }
}
@media (min-width: 1100px) {
	.tool-menu-wide { grid-template-columns: repeat(4, minmax(150px, 1fr)); }
}
@media (min-width: 1240px) {
	/* Six columns and nearly the whole window: with twenty-two groups the
	   panel was a tall scroll no matter how many columns it had. Anchored to
	   the right edge of the bar, so the width is capped to keep its left edge
	   on screen. */
	.tool-menu-wide {
		grid-template-columns: repeat(6, minmax(150px, 1fr));
		width: 1560px;
	}
}
@media (max-width: 620px) {
	.tool-menu-wide { grid-template-columns: 1fr; }
}
.tool-block { display: flex; flex-direction: column; gap: 2px; }

/* A group that takes the whole width under the columns, laying its options out
   in rows instead of one tall stack. The heading is given a full row of its own
   so the options wrap beneath it rather than beside it, and a rule separates
   the band from the axes above — these are checkboxes among radios, and any
   combination of them can be on. */
.tool-menu-wide .tool-block-full {
	grid-column: 1 / -1;
	flex-direction: row; flex-wrap: wrap; align-items: center;
	gap: 2px 4px;
	margin-top: 10px; padding-top: 8px;
	border-top: 1px solid var(--line);
}
.tool-menu-wide .tool-block-full > .tool-group { flex: 0 0 100%; margin-bottom: 2px; }
/* Menu options are width:100% so they fill their column — in a wrapping row
   that put every one on a line of its own, which is the stack this was meant to
   replace. Here they take only the room their label needs. */
.tool-menu-wide .tool-block-full > button {
	flex: 0 1 auto; width: auto; gap: 8px; padding-right: 14px;
}

.tool-group {
	margin: 10px 12px 4px; font-size: .66rem; font-weight: 800;
	letter-spacing: .16em; text-transform: uppercase; color: var(--muted);
}
.tool-group:first-child { margin-top: 4px; }
.tool-group + button { margin-top: 0; }
/* the single-column language menu keeps its rules between groups; the columned
   appearance menu separates its axes by whitespace instead */
.tool-menu:not(.tool-menu-wide) .tool-group:not(:first-child) {
	border-top: 1px solid var(--line); padding-top: 12px; margin-top: 8px;
}
.tool-menu-wide .tool-block + .tool-block,
.tool-menu-wide .tool-block:first-child { margin-top: 0; }

.swatch { width: 15px; height: 15px; border-radius: 5px; border: 1px solid var(--line-strong); flex: none; }
.swatch-light  { background: #faf6f2; }
.swatch-white  { background: #ffffff; }
.swatch-salmon { background: #e36a54; }
.swatch-dark   { background: #141a25; }
.swatch-night  { background: #0a0e15; }
/* the corner options show their own shape; the photo options their own tone */
.swatch-pill   { background: var(--ink-2); border-radius: 100px; }
.swatch-soft   { background: var(--ink-2); border-radius: 4px; }
.swatch-square { background: var(--ink-2); border-radius: 0; }
.swatch-color  { background: linear-gradient(135deg, #e36a54, #f4cb7b 50%, #667b9a); border-color: transparent; }
.swatch-mono   { background: linear-gradient(135deg, #2b3446, #b9bfc9); border-color: transparent; }
/* each remaining option draws the thing it does: the two typefaces set their
   own initial, the borders show where the line sits, the fills show filled or
   empty, and the hero options show a frame or a play triangle */
.swatch-sans, .swatch-serif, .swatch-instrument, .swatch-prata, .swatch-garamond {
	background: transparent; border-color: transparent;
	display: inline-grid; place-items: center; width: 16px; height: 15px;
	font-size: 13px; line-height: 1; color: var(--ink-2); font-style: normal;
}
.swatch-sans::before       { content: 'A'; font-family: var(--stack-sans); font-weight: 800; }
.swatch-serif::before      { content: 'A'; font-family: var(--stack-serif); font-weight: 600; }
.swatch-instrument::before { content: 'A'; font-family: var(--stack-instrument); font-weight: 400; font-size: 15px; }
.swatch-prata::before      { content: 'A'; font-family: var(--stack-prata); font-weight: 400; font-size: 14px; }
.swatch-garamond::before   { content: 'A'; font-family: var(--stack-garamond); font-weight: 600; font-size: 15px; }
/* the three button sizes draw themselves: a bar that loses height and width */
.swatch-normal, .swatch-small, .swatch-xs {
	background: var(--ink-2); border-color: transparent; border-radius: 3px;
	align-self: center;
}
.swatch-normal { width: 15px; height: 11px; }
.swatch-small  { width: 13px; height: 8px; }
.swatch-xs     { width: 11px; height: 5px; }
/* a spark against a still dot */
.swatch-motion { background: transparent; border-color: transparent;
	display: inline-grid; place-items: center; color: var(--brand); font-style: normal; }
.swatch-motion::before { content: 'º6'; font-size: 12px; line-height: 1; }
.swatch-still { background: transparent; border-color: var(--line-strong); }
/* no line against a line */
.swatch-none { background: transparent; border-color: var(--line-strong); }
.swatch-line {
	background: transparent; border-color: transparent; border-radius: 0;
	border-bottom: 2px solid var(--ink-2); align-self: center; height: 8px;
}
/* filled pill against an outlined one */
.swatch-highlight { background: var(--brand); border-color: var(--brand); border-radius: 100px; }
.swatch-plain     { background: transparent; border-color: var(--line-strong); border-radius: 100px; }
/* the three hero lines share one on/off pair: a filled dot or an empty one */
.swatch-on  { background: var(--brand); border-color: var(--brand); }
.swatch-off { background: transparent; border-color: var(--line-strong); }

/* logo colour: the colour itself */
.swatch-ink   { background: var(--ink); }
.swatch-coral { background: var(--brand); }
.swatch-sand  { background: var(--accent-ink); }
.swatch-slate { background: var(--brand-2); }

/* card and picture corners: the corner itself */
.swatch-card-round, .swatch-pic-round { background: var(--ink-2); border-radius: 6px; }
.swatch-card-sharp, .swatch-pic-sharp { background: var(--ink-2); border-radius: 0; }

/* heading width: a long rule and a short one */
.swatch-wide, .swatch-narrow {
	background: var(--ink-2); border-color: transparent;
	border-radius: 2px; align-self: center; height: 4px;
}
.swatch-wide   { width: 17px; }
.swatch-narrow { width: 9px; }

/* card numbers: a filled disc, or an empty one */
.swatch-show { background: var(--brand); border-color: var(--brand); border-radius: 50%; }
.swatch-hide { background: transparent; border-color: var(--line-strong); border-radius: 50%; }

/* logo size: three bars in the wordmark's own proportion */
.swatch-sm, .swatch-md, .swatch-lg {
	background: var(--ink-2); border-color: transparent;
	border-radius: 2px; align-self: center;
}
.swatch-sm { width: 11px; height: 3px; }
.swatch-md { width: 15px; height: 4px; }
.swatch-lg { width: 19px; height: 5px; }
.swatch-full      { background: transparent; border-color: var(--ink-2); }
.swatch-underline { background: transparent; border-color: transparent; border-bottom: 2px solid var(--ink-2); border-radius: 0; }
.swatch-solid     { background: var(--ink-2); border-color: var(--ink-2); }
.swatch-hollow    { background: transparent; border-color: var(--ink-2); border-width: 1.5px; }
.swatch-curves    { background: transparent; border-color: var(--ink-2); border-radius: 3px; }
.swatch-video {
	background: transparent; border-color: transparent;
	display: inline-grid; place-items: center; color: var(--ink-2); font-style: normal;
}
.swatch-video::before { content: '▶'; font-size: 11px; line-height: 1; }
.tool-menu .code {
	margin-left: auto; font-size: .7rem; letter-spacing: .1em;
	text-transform: uppercase; color: var(--muted);
}

/* ------------------------------------------------------------ intro film ---
   Shown once per visitor, over everything, until the film ends or it is
   skipped. It is hidden by default and only revealed by the data-intro flag
   the shell sets before first paint, so a visitor who has already seen it —
   or who has JavaScript off — never gets a blank layer stuck over the site. */
.intro { display: none; }
[data-intro='1'] .intro {
	position: fixed; inset: 0; z-index: 500;
	display: grid; place-items: center;
	background: #000;
	transition: opacity .6s var(--ease);
}
[data-intro='1'] body { overflow: hidden; }
.intro.gone { opacity: 0; pointer-events: none; }
.intro-video { width: 100%; height: 100%; object-fit: cover; }
.intro-skip {
	position: absolute; right: 22px; bottom: 22px;
	padding: 10px 20px; border-radius: var(--pill);
	border: 1.5px solid rgba(255,255,255,.5); background: rgba(255,255,255,.10);
	color: #fff; font-weight: 700; font-size: .9rem; cursor: pointer;
	backdrop-filter: blur(6px);
	transition: background .2s, border-color .2s;
}
.intro-skip:hover { background: rgba(255,255,255,.22); border-color: #fff; }

/* ----------------------------------------------------------------- view ---- */
.nw-view { min-height: 70vh; outline: none; display: block; position: relative; z-index: 2; }
.nw-loading { min-height: 70vh; display: grid; place-items: center; }
.spinner {
	width: 34px; height: 34px; border: 3px solid var(--line);
	border-top-color: var(--brand); border-radius: 50%;
	animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
.status {
	display: flex; align-items: center; gap: 12px; padding: 30px 0;
	color: var(--muted); font-size: .95rem;
}

/* ----------------------------------------------------------------- hero ---- */
.hero {
	position: relative; overflow: hidden;
	min-height: min(88vh, 780px);
	display: flex; align-items: flex-end;
	padding: 140px 0 64px;
	color: #fff;
	isolation: isolate;
}
.hero-photo {
	position: absolute; inset: 0; width: 100%; height: 100%;
	object-fit: cover; z-index: -2;
	animation: heroIn 1.4s var(--ease) both;
}
@keyframes heroIn { from { transform: scale(1.06); } to { transform: scale(1); } }

/* rotating hero: the slides crossfade in place, each drifting slowly inward */
.hero-slides { position: absolute; inset: 0; z-index: -2; overflow: hidden; }
.hero-slides .hero-photo { opacity: 0; animation: none; transition: opacity 1.1s var(--ease); }
.hero-slides .hero-photo.on { opacity: 1; animation: heroDrift 11s var(--ease) both; }
@keyframes heroDrift { from { transform: scale(1.09); } to { transform: scale(1); } }

.hero-dots {
	position: absolute; right: 26px; bottom: 26px; z-index: 3;
	display: flex; align-items: center; gap: 8px;
}
.hero-dot {
	width: 9px; height: 9px; padding: 0; border: 0; border-radius: 50%;
	background: rgba(255,255,255,.45); cursor: pointer;
	transition: background .25s var(--ease), width .25s var(--ease);
}
.hero-dot:hover { background: rgba(255,255,255,.85); }
.hero-dot.on { background: var(--brand); width: 30px; border-radius: 100px; }
.hero::after {
	content: ''; position: absolute; inset: 0; z-index: -1; background: var(--scrim);
}
.hero .eyebrow { color: var(--accent); }
/* The measure keeps the headline off the full 1180px — a title that long is a
   poster, not a paragraph. It was 16ch, which broke the sentence far earlier
   than the window required; at 26ch the line fills the space it has and
   `balance` shares the words evenly between the two lines rather than leaving
   one of them a stub. */
.hero h1 {
	max-width: 26ch; text-wrap: balance;
	text-shadow: 0 2px 26px rgba(0,0,0,.42);
}
/* the page-level highlight ochre disappears against a sunset; over a
   scrimmed photograph the highlight has to be the pale end of the sand ramp */
.hero .hl { color: var(--sand-300); }
.hero .lead { color: rgba(255,255,255,.9); max-width: 46ch; }
.hero-cta { display: flex; gap: 14px; flex-wrap: wrap; margin: 30px 0 44px; }

.hero-stats {
	display: flex; gap: 40px; flex-wrap: wrap;
	border-top: 1px solid rgba(255,255,255,.28); padding-top: 24px;
}
.hero-stat b {
	display: block; font-size: 2.15rem; font-weight: 800; line-height: 1;
	letter-spacing: -.03em;
}
.hero-stat span { font-size: .84rem; color: rgba(255,255,255,.76); }

/* --------------------------------------------------------- hero: variation --
   A seventh axis, offered only where the home hero lives. `curves` is the
   original — rotating photographs under the drawn river. `video` replaces the
   whole composition with a silent loop: the photographs, the dots and the
   curve overlay all step aside, and the scrim stays so the headline keeps its
   contrast. app.js only gives the element a src once this is chosen, so the
   file is never fetched by someone looking at the other variation. */
/* ------------------------------------------------- hero: the three texts ---
   Each line over the hero can be taken away on its own, so the client can see
   the composition with the eyebrow gone, with no headline, or with the lead
   alone. Scoped to the hero: the same classes carry the rest of the site. */
[data-hero-eyebrow='off'] .hero > .wrap > .eyebrow,
[data-hero-title='off']   .hero > .wrap > h1,
[data-hero-lead='off']    .hero > .wrap > .lead { display: none; }

.hero-video { display: none; }
[data-hero='video'] .hero-video {
	display: block;
	position: absolute; inset: 0; width: 100%; height: 100%;
	object-fit: cover; z-index: -2;
}
[data-hero='video'] .hero-slides,
[data-hero='video'] .hero-art,
[data-hero='video'] .hero-dots { display: none; }

/* the dashed course + ribbon their posts trace over photographs.
   One set per slide, each morphing between three states so the water keeps
   moving; only the set belonging to the visible photograph is shown. */
.hero-art { position: absolute; inset: 0; z-index: -1; pointer-events: none; }
.hero-curve {
	position: absolute; inset: 0; width: 100%; height: 100%;
	opacity: 0; transition: opacity 1.1s var(--ease);
}
.hero-curve.on { opacity: 1; }
/* the dashes travel at a speed of their own, set per slide on the element,
   so they never appear locked to the band drifting underneath them */
.river-dash {
	fill: none; stroke: rgba(255,255,255,.85); stroke-width: 2.5;
	stroke-dasharray: 10 12; stroke-linecap: round;
	animation: flow var(--dash-flow, 24s) linear infinite;
}
@keyframes flow { to { stroke-dashoffset: -440; } }
.river-ribbon { fill: var(--brand); opacity: .36; mix-blend-mode: screen; }
/* the white theme's primary is a mid slate, which barely screens over a
   photograph — there the ribbon takes the salmon secondary instead */
[data-theme='white'] .river-ribbon { fill: var(--brand-2); }
/* The curve SVG is deliberately stretched — preserveAspectRatio="none", so the
   river spans whatever width the hero happens to be. That same non-uniform
   scale would squash anything riding it: the isotype would widen with the
   window and the waypoint disc would turn into an ellipse. A symbol's own
   preserveAspectRatio cannot save it, because the distortion is applied to the
   coordinate system the symbol is already inside.

   So the two markers are scaled back by the inverse of the horizontal stretch.
   app.js measures the hero and publishes the ratio as --sx / --sy; scaling x by
   sy/sx leaves the vertical size alone and makes the pair square again. The
   1 / 1 defaults mean that if the script never runs, nothing moves. */
.hero-art { --sx: 1; --sy: 1; }
.river-node, .river-node-in {
	transform-box: fill-box;
	transform-origin: center;
	transform: scaleX(calc(var(--sy) / var(--sx)));
}
.river-node { color: var(--brand); filter: drop-shadow(0 2px 10px rgba(0,0,0,.35)); }
.river-node-in { fill: #fff; }

/* ------------------------------------------------------------- confluence -- */
.confluence {
	background: var(--surface-3); color: #fff; position: relative; overflow: hidden;
	padding: 96px 0;
}
.confluence .mark-iso {
	position: absolute; right: 4%; top: 50%; transform: translateY(-50%);
	width: 300px; color: #fff; opacity: .08;
	transition: color .5s var(--ease), opacity .5s var(--ease), transform .8s var(--ease);
}
/* the whole band is the hover target — the watermark itself is decorative
   and sits behind the copy, so it would be a hard thing to point at */
.confluence:hover .mark-iso {
	color: var(--salmon-400); opacity: .3;
	transform: translateY(-50%) scale(1.04);
}
.confluence blockquote {
	margin: 0; max-width: 22ch;
	font-size: clamp(1.7rem, 3.6vw, 2.7rem); font-weight: 800;
	line-height: 1.16; letter-spacing: -.022em;
}
.confluence blockquote span { color: var(--accent); display: block; max-width: 24ch; }
.confluence figcaption { margin-top: 26px; color: rgba(255,255,255,.66); max-width: 44ch; font-size: .96rem; }

/* ------------------------------------------------------------ wave divider - */
.wave { display: block; width: 100%; height: 56px; color: var(--bg); }
.wave path { fill: currentColor; }
.wave-up { transform: scaleY(-1); }

/* -------------------------------------------------------------- purposes --- */
.purpose-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px; }
.purpose {
	position: relative; overflow: hidden; border-radius: var(--radius);
	background: var(--surface); border: 1px solid var(--line);
	display: flex; flex-direction: column; min-height: 300px;
	transition: transform .25s var(--ease), box-shadow .25s, border-color .25s;
}
.purpose:hover { transform: translateY(-6px); box-shadow: var(--shadow); border-color: transparent; }
/* a screen's ratio rather than a fixed strip, so the picture is taller and
   stays in proportion as the card narrows */
/* What a photograph is of, drawn over its bottom-right corner — the same place
   and the same voice as the captions the client's own originals carry in their
   margin, which a crop cuts off. Small, and white with a shadow under it rather
   than a panel behind it: it has to sit on a bright sky and on a dark stage
   without either one becoming a box.

   It is not `.photo`, so the greyscale axis leaves it alone, and it is
   pointer-transparent, so it never eats a click meant for the card. */
.photo-tag {
	position: absolute; top: 12px; right: 9px; z-index: 2;
	/* up the right-hand margin, reading bottom to top — the way the captions on
	   the client's own originals are set. vertical-rl runs the line downwards;
	   the half turn is what makes it climb instead, glyphs and all. */
	writing-mode: vertical-rl; transform: rotate(180deg);
	font-family: Inter, Arial, Helvetica, sans-serif;
	font-size: 6.5px; line-height: 1; letter-spacing: .06em;
	color: #fff; opacity: .7; text-shadow: 0 1px 3px rgba(0,0,0,.5);
	pointer-events: none; white-space: nowrap;
	/* one column, never two: a long credit that ran out of height was
	   wrapping into a second line beside the first */
}
/* Over a pale corner — a screenshot of a dashboard, a white sky — white on
   white is no caption at all. The shadow flips with the ink, so the letters
   keep an edge either way. */
.photo-tag.on-light {
	color: #1b2230; text-shadow: 0 1px 2px rgba(255,255,255,.7);
}

/* On a hero the bar is over the picture and the social rail is down its right
   edge, so the tag starts below the one and inside the other. */
.hero .photo-tag { top: 98px; right: 62px; font-size: 7.5px; }

.purpose-img { position: relative; aspect-ratio: 16 / 9; overflow: hidden; }
.purpose-img img { width: 100%; height: 100%; object-fit: cover; transition: transform .5s var(--ease); }
.purpose:hover .purpose-img img { transform: scale(1.06); }
.purpose-body { padding: 22px 24px 26px; display: flex; flex-direction: column; flex: 1; }
.purpose-body h3 { margin-bottom: 6px; }
.purpose-body p { color: var(--ink-2); font-size: .96rem; margin-bottom: 16px; }
.purpose-more {
	margin-top: auto; font-weight: 700; color: var(--brand); font-size: .9rem;
	display: inline-flex; align-items: center; gap: 7px;
}
.purpose:hover .purpose-more { gap: 12px; }
.purpose-more svg { width: 15px; height: 15px; }

/* --------------------------------------------------------------- pillars --- */
.pillars { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
.pillar {
	background: var(--surface); border: 1px solid var(--line);
	border-radius: var(--radius); padding: 30px 28px 32px; position: relative;
}
/* The grid stretches each card to the tallest in the row and .pillar-inner
   takes all of that, but the front face kept its natural height — so a shorter
   card's panel stopped short of the bottom of its cell. */
.pillars .pillar-face.front { height: 100%; }
.pillar-n {
	width: 56px; height: 56px; border-radius: 50%; background: var(--brand);
	color: var(--on-brand); display: grid; place-items: center;
	font-size: 1.6rem; font-weight: 800; margin-bottom: 20px;
	box-shadow: var(--shadow-sm);
}
/* Card titles keep their weight when the typeface axis steps headings down
   (the serif options take every heading to 600, and the two display faces to
   400) — that left a card's title reading like its own body copy. */
.pillar h3,
.pillar-face.back h3,
.card h3 { font-weight: var(--card-title-w, 800); }
.pillar h3 { color: var(--brand); margin-bottom: 16px; }
.pillar > p { color: var(--ink-2); font-size: .96rem; }
.pillar ul { list-style: none; margin: 18px 0 0; padding: 0; }
.pillar li {
	padding: 12px 0; border-top: 1px solid var(--line);
	font-size: .95rem; color: var(--ink-2); line-height: 1.45;
}
/* the elaborated version used on Nosotros */
.pillar-full { padding: 34px 36px 38px; }

/* An image marked as a card is still an image, so it follows the picture axis
   rather than the card one; img.photo outranks .card on specificity. Pictures
   whose container already clips them keep square corners, or they would round
   inside a panel that is not rounded in the same place. */
img.photo { border-radius: var(--radius-img); }
.hero img.photo,
.purpose img.photo,
.season-shot img.photo,
.pillar-face.back img.photo,
.partner-shot img.photo,
.exp-shot img.photo { border-radius: 0; }

/* ------------------------------------------------------------------ cards -- */
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 28px; }

/* ------------------------------------------------- two-column bands ------
   A band whose heading has been hoisted out of its column so that the width
   axis can reach it — see views/*.html, .band-head. Three children, always in
   this order: the heading, then the two columns in source order.

   The gaps are here rather than inline because row-gap has to be nothing: the
   heading is a row of its own, and an inline `gap` shorthand would beat any
   rule trying to close it. */
.band-split {
	display: grid; grid-template-columns: 1fr 1fr;
	column-gap: 48px; row-gap: 0; align-items: center;
}
.band-split-top { align-items: start; }
.band-split > .band-head { grid-column: 1; grid-row: 1; }
.band-split > :nth-child(2) { grid-column: 1; grid-row: 2; }
.band-split > :nth-child(3) { grid-column: 2; grid-row: 1 / span 2; }
/* the bands that put their picture first */
.band-split-rev > .band-head { grid-column: 2; }
.band-split-rev > :nth-child(2) { grid-column: 1; grid-row: 1 / span 2; }
.band-split-rev > :nth-child(3) { grid-column: 2; grid-row: 2; }

/* the whole point: on `wide` the heading runs the width of the band and the
   two columns move underneath it */
[data-headw='wide'] .band-split > .band-head { grid-column: 1 / -1; }
[data-headw='wide'] .band-split > :nth-child(2),
[data-headw='wide'] .band-split > :nth-child(3) { grid-row: 2; }
[data-headw='wide'] .band-split > :nth-child(2) { grid-column: 1; }
[data-headw='wide'] .band-split > :nth-child(3) { grid-column: 2; }
/* the copy belongs under the heading it follows, not floating in the middle of
   a row as tall as the picture beside it */
[data-headw='wide'] .band-split > :nth-child(2) { align-self: start; }
[data-headw='wide'] .band-split-rev > :nth-child(2) { align-self: center; }
[data-headw='wide'] .band-split-rev > :nth-child(3) { align-self: start; }

.band-head { margin-bottom: 20px; }
/* two or more buttons closing a band column — they wrap rather than overflow
   the half-width the split gives them */
.band-actions { display: flex; flex-wrap: wrap; gap: 12px; }
/* "Leer más" as a link inside the paragraph rather than a button under it: it
   is a control, so it is still a <button>, but it wears the text's own type and
   sits on the line where the sentence ends. */
.link-more {
	border: 0; background: none; padding: 0; margin-left: .35em;
	font: inherit; color: var(--brand); cursor: pointer;
	text-decoration: underline; text-underline-offset: .18em;
	text-decoration-thickness: 1px; text-decoration-color: color-mix(in srgb, var(--brand) 45%, transparent);
}
.link-more:hover { text-decoration-color: currentColor; }
.link-more:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 2px; }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px; }
.grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; }
.card {
	background: var(--surface); border: 1px solid var(--line);
	border-radius: var(--radius); overflow: hidden;
}
.pad { padding: 28px; }

.chip {
	display: inline-block; padding: 5px 12px; border-radius: var(--pill);
	font-size: .75rem; font-weight: 700; background: var(--surface-2);
	color: var(--ink-2);
}
.chip-brand { background: var(--brand-soft); color: var(--brand-strong); }
.chip-blue  { background: var(--blue-soft); color: var(--blue); }
/* Event type. Its own tone so it is not read as the area chip beside it; both
   tokens already flip with the theme. */
.chip-type  { background: var(--surface-2); color: var(--ink-2); }
.chip-sand  { background: color-mix(in srgb, var(--accent) 26%, transparent); color: var(--accent-ink); }

/* How the public gets in. Three tones the eye can sort at a glance while
   scrolling the agenda: the door is open, you sign up first, or somebody has
   to buy something (that last one is chip-brand, already defined above).

   chip-quiet is the important one. Four fifths of the agenda has no admission
   recorded, and until now all of it wore a brand-coloured "Consultar" that
   read as an answer. Hollow and dashed says the opposite — this field is
   empty — without hiding the event. */
.chip-go    { background: color-mix(in srgb, var(--go) 16%, transparent); color: var(--go); }
.chip-reg   { background: color-mix(in srgb, var(--reg) 15%, transparent); color: var(--reg); }
.chip-quiet {
	background: transparent; color: var(--muted); font-weight: 600;
	box-shadow: inset 0 0 0 1px var(--line);
}

/* An event's price rows, when the organization has loaded them. */
.price-list { list-style: none; margin: 10px 0 0; padding: 0; }
.price-row {
	display: flex; justify-content: space-between; align-items: baseline; gap: 16px;
	padding: 7px 0; border-bottom: 1px solid var(--line);
}
.price-row:last-child { border-bottom: 0; }
.price-value { white-space: nowrap; }

/* --------------------------------------------------------------- band ------ */
.band-dark { background: var(--surface-3); color: #fff; }
.band-dark h2, .band-dark h3 { color: #fff; }
.band-dark .lead { color: rgba(255,255,255,.78); }
.band-dark .kpi { background: rgba(255,255,255,.07); border-color: rgba(255,255,255,.12); }
.band-dark .kpi span { color: rgba(255,255,255,.66); }
.band-soft { background: var(--bg-2); }

/* ------------------------------------------------------------- directory --- */
.searchbar {
	background: var(--surface); border: 1px solid var(--line);
	border-radius: var(--pill); box-shadow: var(--shadow-sm);
	display: flex; align-items: center; gap: 8px;
	padding: 8px 8px 8px 22px; max-width: 780px;
}
.searchbar svg { width: 20px; height: 20px; color: var(--muted); flex: none; }
.searchbar input {
	border: 0; outline: 0; flex: 1; font: inherit; color: inherit;
	background: transparent; padding: 11px 4px; min-width: 0;
}
.filters { display: flex; gap: 11px; flex-wrap: wrap; margin: 22px 0 10px; }
.select {
	appearance: none; background-color: var(--surface); color: var(--ink-2);
	border: 1px solid var(--line); border-radius: var(--pill);
	padding: 10px 40px 10px 17px; font: inherit; font-size: .9rem; cursor: pointer;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%237d879b' stroke-width='3' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
	background-repeat: no-repeat; background-position: right 15px center;
	max-width: 100%;
}

/* ------------------------------------------------------------- pickers ----
   nw_picker (assets/js/nw_picker.js) — the site's variation of the RCULT85
   nw_select / nw_mselect dropdowns. The control keeps the pill silhouette of
   the .select it replaces so a filter row does not change shape when the
   script upgrades it; everything else is a token, so the five themes and both
   corner shapes carry through without a single rule of their own. */
.pick { position: relative; display: inline-block; text-align: left; max-width: 100%; }
.pick-source { display: none !important; }
/* set by nw_picker while one of the band's menus is open — every section is a
   stacking context of its own, so the band has to be lifted above the ones
   that follow it or the menu is painted over. Still below the header (100). */
section.has-open-pick { z-index: 40; }

.pick-control {
	display: flex; align-items: center; gap: 8px; width: 100%;
	min-height: 44px; padding: 7px 15px 7px 17px;
	background: var(--surface); color: var(--ink-2);
	border: 1px solid var(--line); border-radius: var(--pill);
	font: inherit; font-size: .9rem; text-align: left; cursor: pointer;
	transition: border-color .2s, box-shadow .2s, background .2s;
}
.pick-control:hover { border-color: var(--line-strong); }
.pick.is-open .pick-control,
.pick-control:focus-visible {
	border-color: var(--brand);
	box-shadow: 0 0 0 3px var(--brand-soft);
	outline: none;
}
.pick-value { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pick-caret { width: 15px; height: 15px; flex: none; color: var(--muted); transition: transform .2s var(--ease); }
.pick.is-open .pick-caret { transform: rotate(180deg); }

/* the multiple control is a row of chips that wraps, with the search input
   sharing the last line — it grows downward as choices are added */
.pick-control-multi { flex-wrap: wrap; cursor: text; padding: 5px 15px 5px 8px; }
.pick-many { min-width: 220px; }
.pick-tags { display: contents; }
.pick-tag {
	display: inline-flex; align-items: center; gap: 2px; max-width: 15rem;
	padding: 4px 4px 4px 12px; border-radius: var(--pill);
	background: var(--brand-soft); color: var(--brand-strong);
	font-size: .78rem; font-weight: 700;
	animation: pickIn .18s var(--ease);
}
@keyframes pickIn { from { opacity: 0; transform: translateY(-3px); } }
.pick-tag-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pick-tag-x {
	flex: none; border: 0; padding: 0; width: 19px; height: 19px; cursor: pointer;
	border-radius: 50%; background: transparent; color: inherit;
	font-size: 1.05rem; line-height: 1; opacity: .65;
}
.pick-tag-x:hover { opacity: 1; background: color-mix(in srgb, var(--brand) 20%, transparent); }
.pick-input {
	flex: 1 1 7ch; min-width: 6ch; border: 0; outline: 0; padding: 6px 2px;
	background: transparent; color: inherit; font: inherit; font-size: .9rem;
}
.pick-input::placeholder { color: var(--ink-2); opacity: 1; }

/* ---- the floating menu */
.pick-menu {
	position: absolute; left: 0; top: calc(100% + 6px); z-index: 90;
	width: max-content; min-width: 100%; max-width: calc(100vw - 16px);
	max-height: 320px; overflow-y: auto;
	background: var(--surface); border: 1px solid var(--line);
	border-radius: var(--radius-sm); box-shadow: var(--shadow);
	padding: 6px;
	animation: pickDrop .18s var(--ease) both;
}
.pick-up .pick-menu { top: auto; bottom: calc(100% + 6px); }
@keyframes pickDrop { from { opacity: 0; transform: translateY(-6px); } }

.pick-search {
	display: flex; align-items: center; gap: 9px; position: sticky; top: -6px;
	margin: -6px -6px 6px; padding: 12px 14px;
	background: var(--surface); border-bottom: 1px solid var(--line);
}
.pick-search svg { width: 16px; height: 16px; color: var(--muted); flex: none; }
.pick-search-input {
	flex: 1; border: 0; outline: 0; background: transparent;
	font: inherit; font-size: .92rem; color: var(--ink); min-width: 0;
}

.pick-option {
	display: flex; align-items: center; gap: 10px; cursor: pointer;
	padding: 9px 12px; border-radius: var(--pill-sm);
	font-size: .92rem; color: var(--ink-2);
}
.pick-option:hover, .pick-option.is-active { background: var(--surface-2); color: var(--ink); }
.pick-option[aria-selected='true'] { color: var(--brand-strong); font-weight: 700; }
.pick-option-text { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pick-check { width: 15px; height: 15px; flex: none; color: var(--brand); opacity: 0; }
.pick-option[aria-selected='true'] .pick-check { opacity: 1; }
.pick-empty { margin: 0; padding: 14px 12px; color: var(--muted); font-size: .88rem; }

@media (max-width: 760px) {
	.pick, .pick-many { width: 100%; min-width: 0; }
	.pick-tag { max-width: 11rem; }
}

.dir-card { display: flex; flex-direction: column; transition: transform .2s var(--ease), box-shadow .2s; }
.dir-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-sm); }
.dir-cover { height: 92px; position: relative; overflow: hidden; }
.dir-cover::after {
	content: ''; position: absolute; inset: 0;
	background-image: var(--grain); opacity: .22; mix-blend-mode: overlay;
}
.dir-avatar {
	width: 62px; height: 62px; border-radius: 50%;
	border: 4px solid var(--surface); margin: -34px 0 0 22px;
	display: grid; place-items: center; color: #fff;
	font-size: 1.35rem; font-weight: 800; box-shadow: var(--shadow-sm);
	position: relative; z-index: 1;
}
.dir-body { padding: 12px 22px 24px; }
.dir-body h3 { font-size: 1.08rem; margin-bottom: 4px; }
.dir-meta {
	font-size: .86rem; color: var(--muted); margin-bottom: 13px;
	display: flex; gap: 6px; align-items: center;
}
.dir-meta svg { width: 15px; height: 15px; flex: none; }
.dir-tags { display: flex; gap: 6px; flex-wrap: wrap; }
.tone-1 { background: var(--salmon-500); } .tone-2 { background: var(--slate-500); }
.tone-3 { background: var(--blue-500); }   .tone-4 { background: var(--sand-500); }
.tone-5 { background: var(--blue-300); }

/* ------------------------------------------------------------- dashboard --- */
.kpi-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; margin-bottom: 30px; }
.kpi {
	background: var(--surface); border: 1px solid var(--line);
	border-radius: var(--radius); padding: 24px 26px;
}
.kpi b { font-size: 2.2rem; font-weight: 800; line-height: 1; display: block; letter-spacing: -.03em; }
.kpi span { font-size: .84rem; color: var(--muted); }

.chart-card {
	background: var(--surface); border: 1px solid var(--line);
	border-radius: var(--radius); padding: 24px 26px 40px;
}
.chart-card h3 { font-size: 1rem; font-weight: 800; margin-bottom: 3px; }
.chart-card .muted { font-size: .82rem; margin-bottom: 22px; }
.bars { display: flex; align-items: flex-end; gap: 12px; height: 180px; padding-top: 22px; }
.bar {
	flex: 1; border-radius: 9px 9px 4px 4px; position: relative; min-width: 8px;
	background: var(--brand); transition: height .7s var(--ease);
}
.bar.b2 { background: var(--slate-500); } .bar.b3 { background: var(--blue-500); }
.bar.b4 { background: var(--sand-500); }  .bar.b5 { background: var(--blue-300); }
.bar b { position: absolute; top: -21px; left: 0; right: 0; text-align: center; font-size: .74rem; font-weight: 800; color: var(--ink-2); }
.bar span { position: absolute; bottom: -26px; left: -4px; right: -4px; text-align: center; font-size: .7rem; color: var(--muted); }
.dash-scope { font-size: 1.3rem; margin: 0 0 18px; }
.note {
	display: flex; gap: 13px; align-items: center; background: var(--surface-2);
	border-radius: var(--radius-sm); padding: 15px 19px; font-size: .92rem;
	color: var(--ink-2);
}
.note svg { width: 20px; height: 20px; color: var(--brand); flex: none; }

/* ---------------------------------------------------------------- agenda --- */
.agenda-list { display: flex; flex-direction: column; gap: 14px; }
.evt {
	/* flex, not a fixed grid: the picture is optional, and a grid with a
	   named third column pushes a fourth child onto its own row the moment one
	   card has a thumbnail and the next does not. */
	display: flex; gap: 22px; align-items: center;
	background: var(--surface); border: 1px solid var(--line);
	border-radius: var(--radius); padding: 18px 22px;
	transition: box-shadow .2s, transform .2s, border-color .2s;
}
.evt:hover { box-shadow: var(--shadow-sm); transform: translateX(4px); border-color: var(--line-strong); }

/* The season an event belongs to, as a line down the side of its row. The
   colour is chosen by the network and arrives per event in --season, so the
   rule cannot hard-code it; a row with no season keeps the plain border and no
   pill, because a default colour would read as a season of its own. */
.evt-has-season { border-left: 4px solid var(--season, var(--line)); }
/* Since 2026-09-01 the pill carries the season's CODE — tcm2026, tcu2026 — with
   the full name in its tooltip, so the colour has to do the identifying on its
   own. The ink is the season's own colour pulled most of the way toward the
   page's, which keeps it legible whatever hue the network picked: a flat fill
   with white on it would be a contrast gamble against a pale one. */
.chip-season {
	background: color-mix(in srgb, var(--season, var(--brand)) 20%, transparent);
	color: color-mix(in srgb, var(--season, var(--brand)) 45%, var(--ink));
	border: 1px solid color-mix(in srgb, var(--season, var(--brand)) 48%, transparent);
	white-space: nowrap; cursor: help;
}
.evt[role='button'] { cursor: pointer; }
.evt-date {
	text-align: center; background: var(--brand-soft); color: var(--brand-strong);
	border-radius: var(--radius-sm); padding: 12px 6px;
}
.evt-date { flex: 0 0 82px; }
/* A fixed square the picture FILLS: cover crops what will not fit and centre
   decides what survives, so nothing is ever stretched out of shape. */
.evt-thumb {
	flex: 0 0 96px; inline-size: 96px; block-size: 96px;
	border-radius: var(--radius-sm); overflow: hidden; background: var(--brand-soft);
}
.evt-thumb img { inline-size: 100%; block-size: 100%; object-fit: cover; object-position: center; display: block; }
.evt-main { flex: 1 1 auto; min-inline-size: 0; }
.evt-date b { display: block; font-size: 1.7rem; font-weight: 800; line-height: 1; }
.evt-date span { font-size: .7rem; text-transform: uppercase; letter-spacing: .12em; }
.evt-main h3 { font-size: 1.12rem; margin-bottom: 5px; }
.evt-meta { font-size: .85rem; color: var(--muted); display: flex; gap: 12px; flex-wrap: wrap; align-items: center; }
.evt-meta svg { width: 15px; height: 15px; vertical-align: -2px; }

.modal { position: fixed; inset: 0; z-index: 200; display: flex; align-items: center; justify-content: center; padding: 22px; }
.modal[hidden] { display: none; }
.modal-overlay { position: absolute; inset: 0; background: rgba(12,16,23,.6); backdrop-filter: blur(3px); }
.modal-card {
	position: relative; background: var(--surface); border-radius: var(--radius-lg);
	max-width: 660px; width: 100%; max-height: 88vh; overflow: auto;
	box-shadow: 0 30px 80px -30px rgba(0,0,0,.6); padding: 34px 36px;
	animation: pop .3s var(--ease) both;
}
/* An event's detail carries more than the other pop-ups do — a picture, the
   admission block, the price rows, a map — so it gets about a third more room
   than the 660px default (asked for 2026-09-01). `width: 100%` is untouched, so
   on anything narrower than this the card still shrinks to the viewport less
   the .modal padding, exactly as before. */
.modal-card-wide { max-width: 860px; }

@keyframes pop { from { transform: translateY(14px) scale(.98); opacity: 0; } }
.modal-x {
	position: absolute; top: 14px; right: 18px; border: 0; background: transparent;
	font-size: 1.9rem; line-height: 1; color: var(--muted); cursor: pointer;
}
.modal-x:hover { color: var(--ink); }
.ag-when, .ag-where { display: flex; align-items: center; gap: 10px; font-size: .95rem; margin: 6px 0; color: var(--ink-2); }
.ag-when svg, .ag-where svg { width: 18px; height: 18px; color: var(--brand); flex: none; }
.ag-block { margin-top: 20px; }
.ag-block h4 { font-size: .95rem; margin-bottom: 7px; }
.ag-block p { font-size: .94rem; color: var(--ink-2); line-height: 1.66; margin: 0; }
.ag-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.ag-actions {
	display: flex; flex-wrap: wrap; gap: 10px; margin-top: 26px;
	border-top: 1px solid var(--line); padding-top: 22px;
}

/* ------------------------------------------------------------- showcase ---- */
.masonry { columns: 3; column-gap: 22px; }
.show-item {
	break-inside: avoid; margin-bottom: 22px; border-radius: var(--radius);
	overflow: hidden; border: 1px solid var(--line); background: var(--surface);
	box-shadow: var(--shadow-sm); position: relative;
	transition: transform .25s var(--ease), box-shadow .25s;
}
.show-item:hover { transform: translateY(-5px); box-shadow: var(--shadow); }
.show-item img { width: 100%; height: auto; }
/* leaves room for the rail so copy never runs under it */
.show-body { padding: 18px 48px 22px 20px; }
.show-body h3 { font-size: 1.1rem; margin: 10px 0 6px; }
.show-body p { font-size: .93rem; color: var(--ink-2); margin: 0; }
/* the vertical caption rail down the right edge of their post images */
.show-rail {
	position: absolute; top: 0; right: 0; width: 26px; height: 100%;
	background: var(--brand); color: var(--on-brand);
	display: grid; place-items: center; pointer-events: none;
}
.show-rail span {
	writing-mode: vertical-rl; font-size: .62rem; font-weight: 800;
	letter-spacing: .16em; text-transform: uppercase; white-space: nowrap;
}

/* -------------------------------------------------------------- territory -- */
.territory { position: relative; overflow: hidden; }
/* Antioquia as its nine subregions, injected from
   assets/brand/svg/antioquia-subregions.svg. Each path is one subregion, and
   carries its census name in data-zone so the chips and the map answer to the
   same handle. The hairline stroke in the page colour hides the municipal
   borders inside a subregion, which are still there as separate subpaths. */
.territory-map {
	width: 100%; max-width: 460px;
	filter: drop-shadow(0 24px 40px rgba(0,0,0,.14));
}
.territory-map svg { width: 100%; height: auto; display: block; overflow: visible; }
.territory-map [data-zone] {
	fill: var(--blue); opacity: .92;
	/* Each subregion is one path made of its municipalities, so this hairline
	   draws every municipal border too. Kept, but faint: the subregion reads as
	   a block and the towns inside it stay as texture rather than as structure. */
	stroke: color-mix(in srgb, var(--bg) 55%, transparent);
	stroke-width: .8; stroke-linejoin: round;
	transition: fill .18s var(--ease), opacity .18s;
	cursor: pointer;
}
.territory-map [data-zone]:hover,
.territory-map [data-zone].on { fill: var(--brand); opacity: 1; }
/* the census figures for a subregion, shown while it is pointed at */
.subregion { position: relative; cursor: default; transition: background .2s, color .2s, border-color .2s; }
.subregion.on { background: var(--brand); color: var(--on-brand); border-color: var(--brand); }
.subregion-stat {
	display: block; min-height: 1.5em; margin-top: 16px;
	font-size: .93rem; color: var(--ink-2);
}
.subregion-stat b { color: var(--brand); font-weight: 800; }
.subregion-stat.is-empty { opacity: .55; }
/* a figure standing in for the census is marked as such, every line of it */
.stat-pending {
	font-size: .8em; font-weight: 700; letter-spacing: .02em;
	color: var(--accent-ink); white-space: nowrap;
}

.subregions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 26px; }
.subregion {
	padding: 10px 18px; border-radius: var(--pill); font-weight: 700; font-size: .9rem;
	background: var(--surface); border: 1px solid var(--line); color: var(--ink-2);
	transition: background .2s, color .2s, border-color .2s, transform .2s;
}
.subregion:hover { transform: translateY(-2px); background: var(--brand); color: var(--on-brand); border-color: transparent; }

/* ---------------------------------------------------------------- allies --- */
.marquee { overflow: hidden; position: relative; padding: 8px 0; --fade: 90px; }
.marquee::before, .marquee::after {
	content: ''; position: absolute; top: 0; bottom: 0; width: var(--fade); z-index: 2;
	pointer-events: none;
}
.marquee::before { left: 0; background: linear-gradient(90deg, var(--bg-2), transparent); }
.marquee::after { right: 0; background: linear-gradient(270deg, var(--bg-2), transparent); }
.marquee-track { display: flex; align-items: center; gap: 56px; width: max-content; animation: slide 64s linear infinite; }
.marquee:hover .marquee-track { animation-play-state: paused; }
@keyframes slide { to { transform: translateX(-50%); } }
.ally-img { height: 46px; width: auto; opacity: .78; transition: opacity .2s; }
.marquee .ally-img:hover { opacity: 1; }
/* the marks are ink-on-transparent originals, unreadable on a dark surface —
   both dark themes flip them to white */
[data-theme='dark'] .ally-img,
[data-theme='night'] .ally-img { filter: brightness(0) invert(1); opacity: .78; }
[data-theme='dark'] .ally-img:hover,
[data-theme='night'] .ally-img:hover { opacity: 1; }

.ally-cell {
	display: grid; place-items: center; min-height: 96px; padding: 18px;
	background: var(--surface); border: 1px solid var(--line);
	border-radius: var(--radius-sm);
}
.ally-cell .ally-img { height: 40px; }

/* --------------------------------------------------------- video + docs ----
   A 16:9 box for an embedded film, and the list of documents on #/informes.
   Both are page furniture rather than components of their own: one aspect-ratio
   and one row, in the tokens everything else already uses. */
.video-frame { position: relative; aspect-ratio: 16 / 9; width: 100%; }
.video-frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
/* the film in a panel over the page: wider than a reading modal, and no padding
   between the frame and the panel edge — the film is the content */
.modal-card-video {
	max-width: min(1040px, 92vw); padding: 0; overflow: visible;
	background: #000; border-radius: var(--radius);
}
.modal-card-video .modal-x {
	top: -44px; right: -4px; color: rgba(255,255,255,.86); font-size: 2.2rem;
}
.modal-card-video .modal-x:hover { color: #fff; }
.modal-card-video .video-frame { border-radius: var(--radius); overflow: hidden; }

/* Numbered steps — how to donate. An ordered list that keeps its own numbers,
   since the disc beside each step is the number and the list must still read as
   a sequence when the stylesheet is gone. */
.steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.step {
	display: grid; grid-template-columns: auto 1fr; gap: 22px; align-items: start;
	padding: 26px 0; border-top: 1px solid var(--line);
}
.step:last-child { border-bottom: 1px solid var(--line); }
.step-n {
	width: 46px; height: 46px; border-radius: var(--radius-sm);
	background: var(--brand); color: var(--on-brand);
	display: grid; place-items: center; font-size: 1.3rem; font-weight: 800;
}
.step-body h3 { margin-bottom: 6px; }
.step-body p { color: var(--ink-2); margin: 0 0 12px; }
.step-data {
	display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px;
	padding: 14px 18px; background: var(--surface); border: 1px solid var(--line);
	border-radius: var(--radius-sm);
}
.step-data span { font-size: .86rem; color: var(--muted); }
.step-data b { font-size: 1.1rem; letter-spacing: .04em; color: var(--brand-strong); }
.step-list { margin: 0 0 16px; padding-left: 20px; color: var(--ink-2); font-size: .95rem; }
.step-list li { margin-bottom: 4px; }
@media (max-width: 620px) {
	.step { grid-template-columns: 1fr; gap: 14px; }
}

/* A page that has been announced but has nothing on it yet: the sentence
   saying so carries its own mark, on the line where it starts. */
.soon-lead { display: flex; align-items: flex-start; gap: 12px; }
.soon-lead .ico {
	width: 24px; height: 24px; flex: none; color: var(--brand);
	margin-top: .18em;                /* optical, against the first line */
}

.report-list { display: grid; gap: 12px; }
.report-item {
	display: flex; align-items: center; justify-content: space-between; gap: 20px;
	padding: 20px 24px; background: var(--surface); border: 1px solid var(--line);
	border-radius: var(--radius-sm); color: var(--ink);
	transition: border-color .2s, transform .2s, box-shadow .2s;
}
.report-item:hover {
	border-color: var(--brand); transform: translateY(-2px); box-shadow: var(--shadow-sm);
}
.report-body { display: grid; gap: 4px; }
.report-name { font-weight: 700; }
.report-meta { font-size: .86rem; color: var(--muted); }
.report-dl {
	display: inline-flex; align-items: center; gap: 8px; flex: none;
	font-size: .88rem; font-weight: 700; color: var(--brand);
}
@media (max-width: 620px) {
	.report-item { flex-direction: column; align-items: flex-start; gap: 12px; }
}

/* ------------------------------------------------------------- cta band ----
   Edge to edge: the band sits outside .wrap in the three views that carry it,
   so the colour runs the width of the page and its own padding holds the words
   to the measure. It rests in the theme's blue and turns to the salmon gradient
   under the pointer — the whole band, not just a button, which is what "cuando
   la persona pase por encima" describes.

   Everything inside follows `color`, so the two states need no rules of their
   own: the heading, the lead and the outline buttons all inherit. */
.cta-band {
	position: relative; overflow: hidden;
	padding: 62px 24px; text-align: center;
	background: var(--cta-bg); color: var(--cta-ink);
	transition: background .35s var(--ease), color .35s var(--ease);
}
.cta-band:hover,
.cta-band:focus-within {          /* the keyboard reaches it too */
	background: var(--cta-bg-hover); color: var(--cta-ink-hover);
}
.cta-band::after {
	content: ''; position: absolute; inset: 0;
	background-image: var(--grain); opacity: .12; mix-blend-mode: overlay;
}
.cta-band > * { position: relative; z-index: 1; }
.cta-band h2 { color: inherit; }
.cta-band .lead { color: inherit; opacity: .88; max-width: 54ch; margin: 0 auto 28px; }
.cta-actions { display: flex; gap: 14px; flex-wrap: wrap; justify-content: center; }
/* the buttons are outlines of whatever ink the band currently has */
.cta-band .btn-dark,
.cta-band .btn-on-photo,
[data-fill='hollow'] .cta-band .btn-dark,
[data-fill='hollow'] .cta-band .btn-primary {
	background: color-mix(in srgb, currentColor 8%, transparent);
	color: inherit; border-color: color-mix(in srgb, currentColor 55%, transparent);
	box-shadow: none;
}
.cta-band .btn-dark:hover,
.cta-band .btn-on-photo:hover,
[data-fill='hollow'] .cta-band .btn-dark:hover,
[data-fill='hollow'] .cta-band .btn-primary:hover {
	background: color-mix(in srgb, currentColor 18%, transparent);
	border-color: currentColor; color: inherit;
}

/* ---------------------------------------------------------------- footer --- */
.site-footer { background: var(--surface-3); color: rgba(255,255,255,.72); padding: 74px 0 28px; position: relative; z-index: 2; }
.site-footer .mark-logo { width: 190px; color: #fff; }
.footer-grid {
	display: grid; grid-template-columns: 1.7fr 1fr 1fr 1.2fr; gap: 38px;
	padding-bottom: 42px; border-bottom: 1px solid rgba(255,255,255,.12);
}
.footer-tag { margin-top: 20px; font-size: .93rem; max-width: 34ch; }
.footer-col h4 {
	font-size: .74rem; text-transform: uppercase; letter-spacing: .16em;
	color: rgba(255,255,255,.5); margin-bottom: 15px;
}
.footer-col a, .footer-col p { display: block; padding: 5px 0; margin: 0; font-size: .93rem; color: rgba(255,255,255,.72); }
.footer-col a { transition: color .2s; }
.footer-col a:hover { color: #fff; }
.footer-bottom {
	display: flex; justify-content: space-between; gap: 14px; flex-wrap: wrap;
	align-items: center;
	padding-top: 24px; font-size: .82rem; color: rgba(255,255,255,.5);
}
.footer-by { display: inline-flex; align-items: center; gap: 10px; transition: color .2s; }
.footer-by img { width: 20px; height: 20px; flex: none; opacity: .75; transition: opacity .2s; }
.footer-by:hover { color: #fff; }
.footer-by:hover img { opacity: 1; }

/* ------------------------------------------------------------ pillar flip -
   On the home page each line of work is a card that rests on its photograph —
   the picture, the name of the eje and a way in — and turns over to the list of
   what it does when the pointer lands on it. Clicking goes to the fuller
   version on Nosotros.

   The two faces are the other way round from how they read in the markup, and
   deliberately so: the list is the taller of the two and it is the face that
   sits in the flow, so it is what gives the card its height. The photograph is
   absolutely positioned over that box, which is why turning the container the
   other way costs one line instead of a rebuild. */
.pillar-flip {
	display: block; perspective: 1400px; position: relative;
	color: inherit; cursor: pointer;
}
/* The card used to take its height from the list face alone, which left it
   about a third shorter than the photograph behind it: the shots in
   assets/img/pillars are portraits (1529x2050) and `cover` was cutting the top
   and the bottom off every one of them, so the resting face read as a picture
   someone had trimmed. The card now carries the ratio of the photograph
   itself, so nothing is cut at any column width — and because a grid item with
   a ratio still respects its own content, a longer list in another language
   grows the card rather than spilling out of it. */
.pillars .pillar-flip { aspect-ratio: 1529 / 2050; }
.pillar-inner {
	position: relative; transform-style: preserve-3d;
	transition: transform .7s var(--ease); height: 100%;
	transform: rotateY(180deg);          /* at rest: the photograph */
}
/* Hovering used to turn the card over at once, which threw away the thing the
   pointer had just bought: these photographs are greyscale until they are
   pointed at, so the colour arrived on a face that was already turning away.
   The pointer now tilts the card twenty degrees and leaves it there — the
   picture in colour, at an angle — and only a pointer that stays turns it over
   to the list. app.js counts the five seconds (.is-turned); the two states are
   ordered so the turn wins while both classes are on the card.

   The keyboard does not wait: focus goes straight to the list, since a reader
   arriving by tab is after what the card says, not the photograph. */
.pillar-flip.is-peek .pillar-inner {
	transform: rotateY(160deg); transition-duration: .38s;
}
.pillar-flip.is-turned .pillar-inner,
.pillar-flip:focus-visible .pillar-inner {
	transform: rotateY(0deg); transition-duration: .75s;
}
.pillar-face { backface-visibility: hidden; -webkit-backface-visibility: hidden; }
.pillar-face.back {
	position: absolute; inset: 0; transform: rotateY(180deg);
	/* it is a photograph filling the card, so it follows the picture axis */
	border-radius: var(--radius-img); overflow: hidden;
	display: grid; align-items: end;
}
.pillar-face.back img { width: 100%; height: 100%; object-fit: cover; grid-area: 1/1; }
.pillar-face.back .pillar-back-copy {
	/* Pinned to the bottom edge rather than placed in the grid cell: as a grid
	   item it was ending up 41px below the card, which put the `Explorar` link
	   under the clip and — because the gradient is darkest at its own bottom —
	   left only the pale half of the scrim on the card. It looked as though the
	   scrim had gone; it had simply slid off the picture. */
	position: absolute; left: 0; right: 0; bottom: 0;
	padding: 26px;
	/* Taller and heavier at the foot than it was: one stop at .86 fading out by
	   70% left the first line of copy sitting on bare photograph. Four stops
	   over the full height keep the words dark-backed without flattening the
	   picture behind them. */
	background: linear-gradient(0deg,
		rgba(8,11,17,1) 0%,
		rgba(8,11,17,.97) 30%,
		rgba(8,11,17,.78) 60%,
		rgba(8,11,17,.36) 84%,
		rgba(8,11,17,0) 100%);
	color: #fff;
}
/* What arrives after the turn animates in rather than being there already: the
   far face is only facing the visitor about halfway through the flip, so the
   delays start there. It is the list that arrives now, so the stagger runs down
   its three parts — the number, the name and the items. The lead that used to
   sit between the last two went with the client's note of 2026-08-24: it was
   already over the photograph on the face the visitor had just been looking
   at. */
@keyframes pillarTurnIn { from { opacity: 0; transform: translateY(16px); } }
.pillar-flip.is-turned .pillar-face.front > *,
.pillar-flip:focus-visible .pillar-face.front > * {
	animation: pillarTurnIn .42s var(--ease) both;
}
.pillar-flip.is-turned .pillar-face.front > :nth-child(1),
.pillar-flip:focus-visible .pillar-face.front > :nth-child(1) { animation-delay: .30s; }
.pillar-flip.is-turned .pillar-face.front > :nth-child(2),
.pillar-flip:focus-visible .pillar-face.front > :nth-child(2) { animation-delay: .37s; }
.pillar-flip.is-turned .pillar-face.front > :nth-child(3),
.pillar-flip:focus-visible .pillar-face.front > :nth-child(3) { animation-delay: .44s; }
/* the card is a control now, not a link: it takes a focus ring of its own */
.pillar-flip:focus-visible {
	outline: 2px solid var(--accent); outline-offset: 4px; border-radius: var(--radius);
}
/* the appearance switch and the visitor's own setting both silence it */
[data-anim='still'] .pillar-face.front > * { animation: none; }
@media (prefers-reduced-motion: reduce) {
	.pillar-flip.is-turned .pillar-face.front > *,
	.pillar-flip:focus-visible .pillar-face.front > * { animation: none; }
}
.pillar-face.back h3 { color: #fff; margin: 0 0 6px; }
.pillar-face.back p { margin: 0; font-size: .92rem; color: rgba(255,255,255,.82); }

/* ---------------------------------------------------------------- slider --
   Shared by the Nosotros pillars and every experience card. The dot count
   comes from the content, never from a hardcoded number. */
.slider { position: relative; }
.slider-track { position: relative; }
.slide { display: none; }
.slide.on { display: block; animation: slideUp .55s var(--ease) both; }
@keyframes slideUp { from { opacity: 0; transform: translateY(14px); } }

.dots { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.dots.center { justify-content: center; }
.dot {
	width: 9px; height: 9px; padding: 0; border: 0; border-radius: 50%;
	background: var(--line-strong); cursor: pointer;
	transition: background .25s var(--ease), width .25s var(--ease);
}
.dot:hover { background: var(--muted); }
.dot.on { background: var(--brand); width: 30px; border-radius: var(--pill); }

/* ------------------------------------------------------------- experiences -
   Every photograph sits in a frame of the same proportions so the grid stays
   even. The picture is cropped to fill it and, on hover, drifts along
   whichever axis actually overflows — alternating direction each time. */
.exp-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 26px; }
.exp-card {
	background: var(--surface); border: 1px solid var(--line);
	border-radius: var(--radius); overflow: hidden;
	display: flex; flex-direction: column;
	transition: transform .25s var(--ease), box-shadow .25s;
}
.exp-card:hover { transform: translateY(-4px); box-shadow: var(--shadow); }
.exp-frame {
	position: relative; width: 100%; aspect-ratio: 3 / 2; overflow: hidden;
	background: var(--surface-2);
}
.exp-shot {
	position: absolute; inset: 0; opacity: 0;
	transition: opacity .55s var(--ease); pointer-events: none;
}
.exp-shot.on { opacity: 1; }
/* Every photograph gets the same canvas, whatever its own proportions: it
   fills the frame, keeps its aspect, and is cropped evenly around the centre.
   This replaces the slow pan on hover — the frame is the constant now, so a
   portrait and a landscape sit in the grid as the same shape. */
.exp-shot img {
	width: 100%; height: 100%;
	object-fit: cover; object-position: center;
	display: block;
}

.exp-shot.is-placeholder {
	display: grid; place-items: center; text-align: center; padding: 24px;
	background:
		repeating-linear-gradient(45deg, var(--surface-2) 0 12px, var(--bg-2) 12px 24px);
	color: var(--muted);
}
.exp-shot.is-placeholder b {
	display: block; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
	font-size: 1rem; color: var(--ink-2); margin-bottom: 6px;
}
.exp-shot.is-placeholder span { font-size: .84rem; }

.exp-body { padding: 22px 26px 24px; display: flex; flex-direction: column; flex: 1; }
.exp-body h3 { margin-bottom: 8px; }
.exp-lead { color: var(--ink-2); font-size: .95rem; }
.exp-caption {
	min-height: 4.6em; margin: 0 0 16px; font-size: .93rem; color: var(--ink-2);
	border-left: 3px solid var(--brand-soft); padding-left: 14px;
}
.exp-foot { margin-top: auto; display: flex; align-items: center; justify-content: space-between; gap: 14px; }
.exp-count { font-size: .78rem; color: var(--muted); font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------- seasons (MEVT) -
   Upcoming seasons are wide two-column cards that alternate side; the ones
   already over become full-width bands — text and a recording side by side,
   with the season's whole photograph folder underneath. */
.season-list { display: flex; flex-direction: column; gap: 26px; }
.season-card {
	display: grid; grid-template-columns: 1fr 1fr; gap: 0;
	background: var(--surface); border: 1px solid var(--line);
	border-radius: var(--radius); overflow: hidden;
	transition: transform .25s var(--ease), box-shadow .25s;
}
.season-card:hover { transform: translateY(-4px); box-shadow: var(--shadow); }
/* the second card mirrors the first, so the page reads as a column of
   alternating photographs rather than a stack of identical cards */
.season-card:nth-child(even) .season-shot { order: 2; }
.season-shot { position: relative; min-height: 300px; overflow: hidden; }
.season-shot img { width: 100%; height: 100%; object-fit: cover; transition: transform .6s var(--ease); }
.season-card:hover .season-shot img { transform: scale(1.05); }
.season-flag {
	position: absolute; left: 18px; top: 18px; z-index: 1;
	padding: 6px 14px; border-radius: var(--pill);
	background: var(--brand); color: var(--on-brand);
	font-size: .7rem; font-weight: 800; letter-spacing: .13em; text-transform: uppercase;
}
/* the copy is centred against the photograph rather than stretched to its
   height: a short season description would otherwise leave a hole above the
   button */
.season-body { padding: 34px 36px 36px; display: flex; flex-direction: column; justify-content: center; }
.season-body h3 { font-size: 1.5rem; margin-bottom: 12px; }
.season-body .lead { font-size: 1rem; }
.season-body .btn { align-self: flex-start; }
.season-meta {
	display: flex; flex-wrap: wrap; gap: 8px 20px; margin-bottom: 16px;
	font-size: .87rem; color: var(--muted);
}
.season-meta span { display: inline-flex; align-items: center; gap: 7px; }
.season-meta svg { width: 15px; height: 15px; color: var(--brand); flex: none; }
.season-facts { display: flex; flex-wrap: wrap; gap: 7px; margin: 4px 0 26px; }

.season-past { padding-top: 46px; }
.season-past + .season-past { margin-top: 22px; border-top: 1px solid var(--line); }
.season-past-head {
	display: flex; align-items: flex-start; justify-content: space-between;
	gap: 20px; margin-bottom: 26px;
}
.season-past-head h3 { font-size: 1.6rem; margin-bottom: 10px; }
.season-past-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 36px; align-items: start; }
.season-text p { color: var(--ink-2); }
.season-text .btn { margin-top: 10px; }

.season-video { margin: 0; }
.season-video-frame {
	position: relative; border-radius: var(--radius); overflow: hidden;
	aspect-ratio: 16 / 9; background: var(--surface-2);
}
.season-video-frame img { width: 100%; height: 100%; object-fit: cover; }
/* the frame is an <a> since 2026-08-27 */
a.season-video-frame { display: block; cursor: pointer; }
a.season-video-frame:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; }
a.season-video-frame:hover .season-play { background: linear-gradient(180deg, rgba(10,14,21,.20), rgba(10,14,21,.62)); }
/* the recording itself does not exist yet, so the frame says so plainly
   rather than pretending to be a player */
.season-play {
	position: absolute; inset: 0; display: grid; place-content: center;
	justify-items: center; gap: 4px; text-align: center; padding: 16px;
	background: linear-gradient(180deg, rgba(10,14,21,.34), rgba(10,14,21,.72));
	color: #fff;
}
.season-play svg { width: 54px; height: 54px; opacity: .92; }
.season-play b {
	font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
	font-size: .95rem; margin-top: 8px;
}
.season-play small { font-size: .78rem; color: rgba(255,255,255,.74); max-width: 28ch; }
.season-video figcaption { margin-top: 12px; font-size: .88rem; color: var(--muted); }

.season-gallery { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-top: 30px; }
.season-shot-fig { margin: 0; }
.season-gallery figure { margin: 0; border-radius: var(--radius-sm); overflow: hidden; border: 1px solid var(--line); }
.season-gallery img { width: 100%; height: 100%; object-fit: cover; aspect-ratio: 4 / 3; }

/* ---------------------------------------------------------------- allies --- */
.ally-cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
.ally-card {
	display: flex; flex-direction: column; align-items: center; gap: 12px;
	padding: 22px 16px; text-align: center;
	background: var(--surface); border: 1px solid var(--line);
	border-radius: var(--radius-sm);
	transition: transform .2s var(--ease), box-shadow .2s, border-color .2s;
}
.ally-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-sm); border-color: var(--line-strong); }
.ally-card .ally-img { height: 38px; }
.ally-card b { font-size: .78rem; font-weight: 700; color: var(--ink-2); line-height: 1.3; }

.partner-shots { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.partner-shot { border-radius: var(--radius-img); overflow: hidden; border: 1px solid var(--line); }
.partner-shot img { width: 100%; height: 100%; object-fit: cover; aspect-ratio: 4 / 3; }

/* --------------------------------------------------- nosotros hero motion --
   Deliberately not the home page's crossfade: these rise and settle, at twice
   the pace, with the isotype turning over behind them on every change. */
.hero-rise .hero-photo {
	opacity: 0; transform: translateY(4%) scale(1.05); animation: none;
	transition: opacity .7s var(--ease), transform .9s var(--ease);
}
.hero-rise .hero-photo.on { opacity: 1; transform: translateY(0) scale(1); }

/* ----------------------------------------------------------- text animation
   The looks half of assets/js/nw_anim.js. That file decides when something
   plays and hands over two custom properties — --anim-dur for the pass and
   --d for this letter's delay — plus --c for the colour effects. Everything
   below is driven by those, so a new effect is one keyframe block and one
   class, with no JavaScript change.

   .nw-anim wraps the phrase; .nw-anim-c is one letter, present only for the
   effects that need them. Nothing animates until .is-anim lands. */
/* Inline, not inline-block: an inline-block is atomic, so an animated phrase
   could never share a line with the words before it — it jumped to a line of
   its own the moment the whole phrase did not fit, which is what put "la
   cultura con el agua" under "Asociamos de manera natural" on the home hero
   however wide the window was. Inline lets it wrap like ordinary text, and the
   word grouping below still keeps words whole.

   The two whole-phrase effects are the exception: they transform the phrase
   itself, and a transform needs a box to act on. */
.nw-anim { display: inline; }
.nw-anim-tilt, .nw-anim-shine { display: inline-block; }
/* a word of split letters stays on one line; the spaces between words are
   still ordinary break opportunities */
.nw-anim-w { white-space: nowrap; }
/* A phrase that replays on click has to look like it will. The focus ring is
   the standard one, since click also binds Enter and Space. */
.nw-anim[data-anim-when*="click"] { cursor: pointer; }
.nw-anim[data-anim-when*="click"]:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 4px;
	border-radius: 2px;
}
.nw-anim-c {
	display: inline-block; font-style: inherit;
	will-change: transform, opacity, color;
}
/* the letters of a typewriter start absent, not merely transparent */
.nw-anim-typewritter .nw-anim-c { opacity: 0; }
.nw-anim-typewritter.is-anim .nw-anim-c {
	animation: nwType .001s linear var(--d, 0s) forwards;
}
@keyframes nwType { to { opacity: 1; } }

.nw-anim-change-color.is-anim .nw-anim-c {
	animation: nwColor var(--anim-dur, .6s) ease-in-out var(--d, 0s) both;
}
@keyframes nwColor {
	40% { color: var(--c, var(--brand)); }
	60% { color: var(--c, var(--brand)); }
	to  { color: inherit; }
}

.nw-anim-bend.is-anim .nw-anim-c {
	animation: nwBend var(--anim-dur, .6s) ease-in-out var(--d, 0s) both;
}
@keyframes nwBend {
	40% { transform: translateY(-.24em) rotate(-6deg); }
	to  { transform: none; }
}

.nw-anim-flip.is-anim .nw-anim-c {
	animation: nwFlip var(--anim-dur, .6s) ease-in-out var(--d, 0s) both;
}
@keyframes nwFlip {
	50% { transform: rotateX(-90deg); }
	to  { transform: none; }
}

.nw-anim-rise.is-anim .nw-anim-c {
	animation: nwRise var(--anim-dur, .6s) cubic-bezier(.22,.61,.36,1) var(--d, 0s) both;
}
@keyframes nwRise {
	from { transform: translateY(.7em); opacity: 0; }
	to   { transform: none; opacity: 1; }
}

.nw-anim-blur.is-anim .nw-anim-c {
	animation: nwBlur var(--anim-dur, .6s) ease-out var(--d, 0s) both;
}
@keyframes nwBlur {
	from { filter: blur(8px); opacity: 0; }
	to   { filter: none; opacity: 1; }
}

/* whole-phrase effects — no letters involved */
.nw-anim-tilt.is-anim {
	animation: nwTilt var(--anim-dur, .6s) ease-in-out both;
	transform-origin: left center;
}
@keyframes nwTilt {
	35% { transform: rotate(-2.2deg) scale(1.03); }
	to  { transform: none; }
}

/* the sweep rides a gradient through the text, so it needs the text to be
   painted from the background — the fallback colour keeps it readable in the
   moment before the animation starts and after it ends */
/* The letters are painted by the gradient rather than by `color`, so the ends
   of that gradient have to BE the real colour — which is what currentColor
   gives, but only while `color` still holds it. Setting `color: transparent`
   here (as this did) makes currentColor transparent too, and the phrase
   disappears the moment the sweep starts. -webkit-text-fill-color alone hides
   the painted glyph without touching what currentColor means. */
.nw-anim-shine.is-anim {
	background: linear-gradient(100deg,
		currentColor 0%, currentColor 38%,
		color-mix(in srgb, var(--accent) 45%, #fff) 50%,
		currentColor 62%, currentColor 100%);
	background-size: 300% 100%;
	-webkit-background-clip: text; background-clip: text;
	-webkit-text-fill-color: transparent;
	animation: nwShine var(--anim-dur, 1.8s) linear both;
}
@keyframes nwShine {
	from { background-position: 120% 0; }
	to   { background-position: -60% 0; }
}

/* Someone who asked for less motion gets the words and none of the movement.
   nw_anim already refuses to play, but a stray class must not linger. */
@media (prefers-reduced-motion: reduce) {
	.nw-anim, .nw-anim-c { animation: none !important; opacity: 1 !important; }
	.nw-anim-shine.is-anim {
		background: none; -webkit-text-fill-color: currentColor;
	}
}

/* --------------------------------------------------------- convocatorias ---
   Four bands the page grew on 2026-08-27: the road from 2020 to the current
   call, a reel of one film per subregion, what Radar Cultural does for the
   call, and what past editions left behind.

   Anything still waiting on the client wears .pending — the same visible
   marker the territory figures use, so a placeholder can never be mistaken
   for the real thing on a screen someone is reviewing. */
.pending {
	display: inline-flex; align-items: center; gap: 6px;
	font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
	font-size: .74rem; letter-spacing: .02em;
	color: var(--accent-ink); background: var(--brand-soft);
	border: 1px dashed var(--line-strong); border-radius: 100px;
	padding: 3px 10px;
}

/* ---- the timeline -------------------------------------------------------
   A rail down the left with a node per milestone. It is an <ol>: the order is
   the meaning, and a reader who cannot see the rail still gets a numbered
   list. */
.timeline { list-style: none; margin: 0; padding: 0 0 0 30px; position: relative; }
.timeline::before {
	content: ''; position: absolute; left: 5px; top: 6px; bottom: 6px; width: 2px;
	background: linear-gradient(180deg, var(--brand), var(--accent) 60%, transparent);
}
.milestone { position: relative; padding: 0 0 30px; }
.milestone:last-child { padding-bottom: 0; }
.milestone::before {
	content: ''; position: absolute; left: -30px; top: 7px;
	width: 12px; height: 12px; border-radius: 50%;
	background: var(--brand); box-shadow: 0 0 0 4px var(--bg);
}
.milestone-year {
	display: block; font-weight: 800; font-size: .78rem; letter-spacing: .16em;
	color: var(--brand); margin-bottom: 4px;
}
.milestone h3 { margin: 0 0 4px; font-size: 1.1rem; }
.milestone p { margin: 0; color: var(--ink-2); font-size: .96rem; }

/* ---- one film per subregion ---------------------------------------------
   A scroll-snap rail rather than a rotator: nine items is too many to page
   through one at a time, and a rail can be flicked on a phone with no script
   at all. The buttons are an affordance for the pointer, not the mechanism —
   with JavaScript off the rail still scrolls. */
.subvideos-head { display: flex; align-items: end; justify-content: space-between; gap: 20px; }
.subvideos-nav { display: flex; gap: 8px; flex: none; }
.subvideos-nav button {
	width: 40px; height: 40px; border-radius: 50%; cursor: pointer;
	border: 1px solid var(--line-strong); background: var(--surface); color: var(--ink);
	display: grid; place-items: center;
	transition: background .2s var(--ease), border-color .2s var(--ease), opacity .2s;
}
.subvideos-nav button:hover { background: var(--brand); border-color: transparent; color: var(--on-brand); }
.subvideos-nav button[disabled] { opacity: .35; cursor: default; }
.subvideos-nav button[disabled]:hover { background: var(--surface); border-color: var(--line-strong); color: var(--ink); }
.subvideos {
	display: grid; grid-auto-flow: column; grid-auto-columns: minmax(260px, 1fr);
	gap: 20px; margin-top: 26px;
	overflow-x: auto; scroll-snap-type: x mandatory;
	scroll-behavior: smooth; scrollbar-width: thin;
	padding-bottom: 10px;
}
.subvideo { scroll-snap-align: start; }
.subvideo-frame {
	position: relative; aspect-ratio: 16 / 9; border-radius: var(--radius-img);
	background: var(--surface-2); border: 1px solid var(--line);
	display: grid; place-items: center; overflow: hidden;
}
.subvideo-frame .ico { width: 26px; height: 26px; color: var(--brand); }
.subvideo-slot { display: grid; justify-items: center; gap: 7px; text-align: center; padding: 14px; }
.subvideo h3 { margin: 12px 0 0; font-size: 1.02rem; }
.subvideo p { margin: 2px 0 0; color: var(--muted); font-size: .9rem; }

/* ---- what Radar Cultural does for the call ------------------------------ */
.radar-points { list-style: none; margin: 20px 0 26px; padding: 0; display: grid; gap: 12px; }
.radar-points li { display: flex; gap: 11px; align-items: start; color: var(--ink-2); font-size: .98rem; }
.radar-points .ico { flex: none; width: 18px; height: 18px; color: var(--brand); margin-top: 3px; }

/* ---- what past editions left behind -------------------------------------
   A four-up of posts from the Promotora's own Instagram. The embeds are not
   here yet, so each card is a labelled slot at the shape a post will be. */
.ig-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; }
.ig-card {
	border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden;
	background: var(--surface); display: flex; flex-direction: column;
}
.ig-slot {
	aspect-ratio: 1; display: grid; place-items: center; gap: 8px;
	background: var(--surface-2); color: var(--muted); text-align: center; padding: 16px;
}
.ig-slot .ico { width: 24px; height: 24px; color: var(--brand); }
.ig-card-body { padding: 14px 16px 18px; }
.ig-card-body h3 { margin: 0 0 4px; font-size: 1rem; }
.ig-card-body p { margin: 0; color: var(--ink-2); font-size: .92rem; }

@media (max-width: 620px) {
	/* one film fills the screen on a phone, and the arrows go: the rail is
	   flicked, not clicked. */
	.subvideos { grid-auto-columns: 84%; }
	.subvideos-nav { display: none; }
	.subvideos-head { display: block; }
	.timeline { padding-left: 24px; }
	.milestone::before { left: -24px; }
}

/* ------------------------------------------------------------- lightbox ----
   A photograph from the reel, opened. The card is the same .modal the film and
   the event detail use; what changes is that the picture, not a panel, is the
   thing on screen — so the card has no background of its own and the controls
   sit over the dark overlay. */
.gallery-shot { cursor: zoom-in; }
.gallery-shot:focus-visible { outline: 2px solid var(--brand); outline-offset: 4px; }

.modal-card-photo {
	max-width: min(1280px, 94vw); padding: 0; overflow: visible;
	background: transparent; box-shadow: none;
	display: grid; justify-items: center; gap: 12px;
}
.modal-card-photo img {
	max-width: 100%; max-height: 82vh; width: auto; height: auto;
	border-radius: var(--radius); display: block;
	box-shadow: 0 30px 80px -30px rgba(0, 0, 0, .7);
}
.modal-card-photo .modal-x {
	top: -44px; right: -4px; color: rgba(255, 255, 255, .86); font-size: 2.2rem;
}
.modal-card-photo .modal-x:hover { color: #fff; }
.lb-caption {
	margin: 0; color: rgba(255, 255, 255, .8); font-size: .88rem; text-align: center;
}
.lb-caption[hidden] { display: none; }

/* The steppers sit outside the picture on a wide screen and over its edges on
   a narrow one, where there is nowhere else for them to go. */
.lb-nav {
	position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
	width: 46px; height: 46px; border-radius: 50%; cursor: pointer;
	border: 1px solid rgba(255, 255, 255, .28); background: rgba(12, 16, 23, .55);
	color: #fff; display: grid; place-items: center;
	transition: background .2s var(--ease), border-color .2s var(--ease);
}
.lb-nav:hover { background: var(--brand); border-color: transparent; }
.lb-nav[hidden] { display: none; }
.lb-prev { left: -62px; }
.lb-next { right: -62px; }
@media (max-width: 900px) {
	.lb-prev { left: 8px; }
	.lb-next { right: 8px; }
}

/* --------------------------------------------------- grant-call winners ----
   The map on the left with its chips, the answer on the right. The panel is a
   live region, so it must keep its height as the pointer moves between
   subregions or the page jumps under the reader. */
.winners-split {
	display: grid; grid-template-columns: 1fr 1fr; gap: 40px; align-items: start;
}
.winners-split .territory-map { margin-top: 22px; }
.winners-panel {
	background: var(--surface); border: 1px solid var(--line);
	border-radius: var(--radius); padding: 24px 26px; min-height: 320px;
}
.winners-panel h3 { margin: 0 0 4px; }
.winners-panel p { margin: 0 0 14px; font-size: .93rem; }
.winners-scroll { max-height: 340px; overflow-y: auto; }
.winners-table { width: 100%; border-collapse: collapse; font-size: .93rem; }
.winners-table th {
	text-align: left; font-size: .7rem; letter-spacing: .13em; text-transform: uppercase;
	color: var(--muted); font-weight: 800; padding: 0 10px 8px 0;
	position: sticky; top: 0; background: var(--surface);
}
.winners-table td { padding: 9px 10px 9px 0; border-top: 1px solid var(--line); vertical-align: top; }
.winners-table td:first-child { color: var(--ink-2); white-space: nowrap; }

@media (max-width: 860px) {
	.winners-split { grid-template-columns: 1fr; }
	.winners-panel { min-height: 0; }
}

/* ------------------------------------------------------------ temporadas +--
   What the seasons page grew on 2026-08-27: a film in place of a cover
   photograph, a reel of moments under the past band, and a playlist button
   whose playlist has not arrived. */

/* A season card whose cover is a film. It fills the same box the photograph
   would, so the card keeps its proportions either way. */
.season-shot-media {
	position: absolute; inset: 0; width: 100%; height: 100%;
	object-fit: cover; background: var(--surface-2); display: block;
}

/* The playlist button. Not an <a>: there is nowhere to send anyone yet, and a
   link to nothing is worse than a button that says it is waiting. */
.btn.is-pending { cursor: default; opacity: .92; gap: 10px; }
.btn.is-pending:hover { transform: none; }

/* The reel of moments. Same mechanics as the subregion rail on Convocatorias —
   scroll-snap with arrows for the pointer — at the shape of a photograph. */
.gallery-rail {
	display: grid; grid-auto-flow: column; grid-auto-columns: minmax(280px, 1fr);
	gap: 20px; margin-top: 22px;
	overflow-x: auto; scroll-snap-type: x mandatory;
	scroll-behavior: smooth; scrollbar-width: thin; padding-bottom: 10px;
}
.gallery-shot { scroll-snap-align: start; margin: 0; position: relative; }
.gallery-shot img {
	width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
	border-radius: var(--radius-img); display: block;
}

/* The marker has to stay readable where it sits on something dark — over the
   recording's scrim, and inside a button that is itself over a photograph. The
   sand-on-cream version disappears against both. */
.season-play .pending,
.btn.is-pending .pending {
	color: #fff; background: rgba(255, 255, 255, .16);
	border-color: rgba(255, 255, 255, .42);
}
.season-play .pending { margin-top: 6px; }

/* The account and the recording sit side by side above the reel; the empty
   band-head is only there to satisfy .band-split's three-child grid. */
.past-summary { margin-top: 44px; }
/* auto-fit, not two columns: a bucket with an odd number of figures in it
   would otherwise leave a hole where the fourth one was not. */
.past-summary .kpi-row { grid-template-columns: repeat(auto-fit, minmax(148px, 1fr)); }

@media (max-width: 620px) {
	.gallery-rail { grid-auto-columns: 84%; }
}

/* ------------------------------------------------------------------ legal ---
   The privacy policy. A long document rather than a landing page: one measure,
   generous leading, headings that step down clearly, and nothing decorative
   competing with the text.

   `.legal-todo` marks a paragraph the client still has to settle; `.pending`
   inside it is the same visible marker the rest of the site uses. Both are
   deliberately loud — a legal page must never look finished while it still
   has holes in it. */
.legal { padding-top: 8px; }
.legal h2 {
	font-size: 1.32rem; margin: 44px 0 12px; letter-spacing: -.012em;
	padding-top: 22px; border-top: 1px solid var(--line);
}
.legal h2:first-of-type { border-top: 0; padding-top: 0; margin-top: 18px; }
.legal h3 { font-size: 1.06rem; margin: 26px 0 10px; color: var(--brand); }
.legal p { color: var(--ink-2); margin: 0 0 14px; }
.legal b { color: var(--ink); }
.legal a { color: var(--brand); }
.legal-list { margin: 0 0 16px; padding-left: 20px; display: grid; gap: 9px; }
.legal-list li { color: var(--ink-2); }
.legal-updated { font-size: .9rem; color: var(--muted); margin-bottom: 26px; }

/* the note that tells a non-Spanish reader what they are looking at */
.note-lang {
	background: var(--surface-2); border: 1px solid var(--line);
	border-radius: var(--radius); padding: 14px 18px;
	font-size: .92rem; color: var(--ink-2); margin: 0 0 26px;
}

/* still to be settled by the client */
.legal-todo {
	background: var(--brand-soft); border-left: 3px solid var(--brand);
	border-radius: 0 var(--radius) var(--radius) 0;
	padding: 14px 18px; margin: 0 0 16px; font-size: .95rem;
}

/* the one link to it, in the footer's bottom line */
.footer-legal { margin-left: 14px; }

/* ------------------------------------------------------- reveal on scroll -- */
.reveal { opacity: 0; transform: translateY(24px); transition: opacity .7s var(--ease), transform .7s var(--ease); }
.reveal.in { opacity: 1; transform: none; }

/* ------------------------------------------------------------ responsive --- */
@media (max-width: 1080px) {
	.site-nav > a:not(.btn) { padding: 9px 10px; font-size: .89rem; }
	/* the wordmark used to be dropped here for the isotype; now it is the only
	   mark in the header, so it gives up width instead of disappearing */
	.brand { --logo-w: 124px; }
}
@media (max-width: 960px) {
	.purpose-grid, .grid-3, .kpi-row, .pillars { grid-template-columns: 1fr 1fr; }
	.ig-grid { grid-template-columns: 1fr 1fr; }
	.grid-4, .ally-cards { grid-template-columns: 1fr 1fr; }
	.season-card, .season-past-grid { grid-template-columns: 1fr; }
	.season-card:nth-child(even) .season-shot { order: 0; }
	.season-shot { min-height: 0; aspect-ratio: 16 / 9; }
	.season-gallery { grid-template-columns: 1fr 1fr; }
	.masonry { columns: 2; }
	.exp-grid { grid-template-columns: 1fr; }
	.partner-shots { grid-template-columns: 1fr; }
	.footer-grid { grid-template-columns: 1fr 1fr; }
	.confluence .mark-iso { width: 260px; opacity: .05; }
	.hero { min-height: 74vh; padding-top: 120px; }
}
/* The drawer used to start at 760px, but the inline nav stops fitting well
   before that — items whose labels are translated into eleven languages, so
   where it gives out depends on the language, and in the longest ones it was
   pushing the tool buttons past the edge of the window and putting a horizontal
   scrollbar on every page. It starts here instead, at the width where the rest
   of the two-column layouts give up as well — the bar is back to seven items,
   and to short labels ("Datos", not "Datos abiertos"), so what was tuned for
   seven holds again. */
@media (max-width: 960px) {
	.nav-toggle { display: flex; }
	.site-nav {
		position: fixed; inset: 78px 0 auto 0; flex-direction: column;
		align-items: stretch; gap: 2px; background: var(--bg);
		border-bottom: 1px solid var(--line); padding: 16px 22px 24px;
		transform: translateY(-130%); transition: transform .32s var(--ease);
		box-shadow: var(--shadow); max-height: calc(100vh - 78px); overflow: auto;
	}
	.site-nav.open { transform: none; }
	/* The drawer hangs off the header, and over imagery that header redefines
	   --ink to white for its own links — which left this panel with white text
	   on its own light background, invisible. It is a solid panel, so it takes
	   the theme's colours back, the same way the dropdowns do. */
	.site-header.over-media .site-nav {
		--ink: var(--ink-root);
		--ink-2: var(--ink-2-root);
		--surface-2: var(--surface-2-root);
		--brand-soft: var(--brand-soft-root);
		--line: var(--line-root);
		color: var(--ink-root);
	}
	.site-header.over-media .site-nav > a:not(.btn) { color: var(--ink-2-root); }
	.site-header.over-media .site-nav > a:not(.btn).active { color: var(--brand); }
}
@media (max-width: 760px) {
	body { font-size: 16px; }
	section { padding: 60px 0; }
	.brand { --logo-w: 112px; }
	.site-nav > a:not(.btn) { padding: 13px 14px; font-size: 1rem; }
	.nav-cta { margin: 10px 0 0; justify-content: center; }
	.ig-grid,
	.purpose-grid, .grid-2, .grid-3, .grid-4, .kpi-row, .pillars,
	.exp-grid, .ally-cards, .season-gallery, .band-split { grid-template-columns: 1fr; }
	/* one card to the width of the page now, so on a wide phone or a tablet
	   held upright the portrait ratio would make a card taller than the screen
	   it is on. The ratio stays — a telephone-width card shows the whole
	   photograph — with a ceiling for the widths where it would not. */
	.pillars .pillar-flip { max-height: 560px; }
	/* the explicit placement above only makes sense with two columns */
	.band-split > * { grid-column: 1 !important; grid-row: auto !important; }
	.band-split { row-gap: 28px; }
	.band-head { margin-bottom: 0; }
	.season-body { padding: 26px 22px 28px; }
	.season-past-head { flex-direction: column; }
	.evt { grid-template-columns: 66px 1fr; }
	.evt .btn, .evt > span.btn { grid-column: 2; justify-self: start; }
	.masonry { columns: 1; }
	.cta-band { padding: 40px 24px; }
	.footer-grid, .footer-bottom { grid-template-columns: 1fr; }
	.hero { min-height: 82vh; padding: 108px 0 48px; }
	.hero-stats { gap: 26px; }
	.hero-stat b { font-size: 1.75rem; }
	.hero-dots { right: 0; left: 0; bottom: 14px; justify-content: center; }
	.modal-card { padding: 28px 22px; }
	.marquee { --fade: 40px; }
}

@media (prefers-reduced-motion: reduce) {
	*, *::before, *::after {
		animation-duration: .001ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: .001ms !important;
	}
	.reveal { opacity: 1; transform: none; }
	html { scroll-behavior: auto; }
}

/* ================================================================== nw_dash
   The public census dashboard (#/datos), rendered by assets/js/nw_dash.js.
   Everything reads the theme tokens, so all appearance axes keep working. */
#pcd { position: relative; }

.pcd-bar { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-bottom: 14px; }
.pcd-scope { display: inline-flex; gap: 4px; background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--pill); padding: 4px; }
.pcd-scopebtn { border: 0; background: transparent; padding: var(--btn-sm-py) var(--btn-sm-px); border-radius: var(--pill); cursor: pointer; font: inherit; font-weight: 700; font-size: .88rem; color: var(--muted); transition: .15s; }
.pcd-scopebtn.is-active { background: var(--surface); color: var(--ink); box-shadow: 0 2px 8px -3px rgba(0,0,0,.25); }
.pcd-count { font-size: .85rem; color: var(--muted); }

.pcd-filterbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 10px 14px; }
.pcd-addbtn { border: 1px dashed var(--line-strong); background: transparent; color: var(--ink); border-radius: var(--pill-sm); padding: var(--btn-sm-py) var(--btn-sm-px); cursor: pointer; font: inherit; font-weight: 700; font-size: .85rem; white-space: nowrap; transition: .15s; }
.pcd-addbtn:hover { border-color: var(--brand); color: var(--brand); }
.pcd-chips { display: flex; gap: 8px; flex-wrap: wrap; flex: 1; min-width: 100px; }
.pcd-chip { display: inline-flex; align-items: center; gap: 7px; background: var(--brand-soft); border: 1px solid var(--line); color: var(--ink); border-radius: var(--pill); padding: 5px 6px 5px 13px; font-size: .82rem; cursor: pointer; max-width: 340px; }
.pcd-chip > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pcd-chipx { border: 0; background: var(--surface-2); color: var(--ink-2); width: 20px; height: 20px; border-radius: 50%; cursor: pointer; line-height: 1; font-size: .8rem; flex: 0 0 auto; }
.pcd-chipx:hover { background: var(--brand); color: #fff; }
.pcd-clear { border: 0; background: transparent; color: var(--brand); cursor: pointer; font: inherit; font-size: .83rem; font-weight: 700; white-space: nowrap; }

/* Sections index: a sticky left column beside the charts, mirroring the
   network-manager dashboard's #cbi-nav. The list is long enough that a row of
   pills wrapped over three lines and pushed the content down; as a column it
   stays legible and follows the reader down the page. */
.pcd-body { display: flex; gap: 20px; align-items: flex-start; margin-top: 22px; }
.pcd-nav { position: sticky; top: 76px; flex: 0 0 210px; width: 210px;
	display: flex; flex-direction: column; gap: 2px;
	background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
	padding: 8px; max-height: calc(100vh - 96px); overflow: auto; }
.pcd-navttl { font-size: .68rem; text-transform: uppercase; letter-spacing: .07em; color: var(--muted); font-weight: 800; padding: 6px 10px 4px; }
.pcd-nav button { display: block; width: 100%; text-align: left; border: 0; background: transparent;
	color: var(--ink-2); border-radius: var(--pill-sm); padding: 8px 11px; cursor: pointer;
	font: inherit; font-size: .84rem; font-weight: 600; line-height: 1.3; transition: .12s; }
.pcd-nav button:hover { background: var(--surface-2); color: var(--ink); }
.pcd-nav button.is-active { background: var(--brand-soft); color: var(--brand); }
.pcd-content { flex: 1; min-width: 0; }

.pcd-sechead { margin: 34px 0 14px; }
.pcd-sechead h3 { font-size: 1.25rem; margin: 0; }
.pcd-sechead .muted { font-size: .85rem; margin: 4px 0 0; }
.pcd-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.pcd-card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 16px 18px; min-width: 0; }
.pcd-card.is-wide { grid-column: 1 / -1; }
.pcd-cardhead { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; margin-bottom: 6px; }
.pcd-cardttl { margin: 0; font-size: .95rem; font-weight: 700; line-height: 1.3; }
.pcd-cardtools { display: flex; gap: 8px; align-items: center; flex: 0 0 auto; }
.pcd-cardmeta { font-size: .74rem; color: var(--muted); white-space: nowrap; }
.pcd-toggle { display: inline-flex; border: 1px solid var(--line); border-radius: var(--pill-sm); overflow: hidden; }
.pcd-toggle button { border: 0; background: var(--surface); color: var(--muted); cursor: pointer; font: inherit; font-size: .72rem; padding: 4px 9px; }
.pcd-toggle button.is-on { background: var(--brand); color: #fff; }
.pcd-csv { border: 1px solid var(--line); background: var(--surface); color: var(--muted); border-radius: var(--pill-sm); padding: 4px 8px; cursor: pointer; font: inherit; font-size: .68rem; font-weight: 700; }
.pcd-csv:hover { background: var(--brand); border-color: var(--brand); color: #fff; }
.pcd-chartbox { min-height: 60px; }
.pcd-chartbox .apexcharts-canvas { cursor: pointer; }
.pcd-tablebox { display: none; }
.pcd-card.show-table .pcd-chartbox { display: none; }
.pcd-card.show-table .pcd-tablebox { display: block; }
.pcd-tbl { width: 100%; border-collapse: collapse; font-size: .84rem; }
.pcd-tbl td { padding: 6px 8px; border-bottom: 1px solid var(--line); }
.pcd-tbl td:last-child { text-align: right; font-variant-numeric: tabular-nums; }
.pcd-tblbar { height: 6px; border-radius: var(--radius-sm); background: var(--brand); opacity: .85; }

.pcd-stats { display: flex; gap: 10px; flex-wrap: wrap; }
.pcd-stat { flex: 1; min-width: 130px; background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 10px 12px; }
.pcd-stat b { display: block; font-size: 1.3rem; }
.pcd-stat span { display: block; font-size: .75rem; color: var(--muted); }

.pcd-mapcard { position: relative; }
.pcd-mapwrap { display: flex; gap: 16px; align-items: flex-start; flex-wrap: wrap; }
.pcd-map { flex: 1; min-width: 280px; }
.pcd-mapsvg { width: 100%; height: auto; display: block; }
/* The border is drawn in the map's own line colour, not in the surface behind
   it: on a dark page those were the same value, so the municipalities read as
   one shape. */
.pcd-mp { stroke: var(--map-line); stroke-width: .6; cursor: pointer; transition: stroke .1s; }
.pcd-mp:hover { stroke: var(--ink); stroke-width: 1.4; }
.pcd-maplegend { display: flex; flex-direction: column; gap: 5px; flex: 0 0 auto; padding-top: 6px; font-size: .76rem; color: var(--muted); }
.pcd-leglbl { font-weight: 700; text-transform: uppercase; letter-spacing: .05em; font-size: .68rem; }
.pcd-legitem { display: flex; align-items: center; gap: 7px; }
.pcd-legitem i { width: 16px; height: 12px; border-radius: var(--radius-sm); display: inline-block; border: 1px solid var(--line); }
.pcd-maptip { position: absolute; z-index: 20; pointer-events: none; background: var(--surface-3); color: #fff; border-radius: var(--radius-sm); padding: 7px 10px; font-size: .8rem; box-shadow: 0 8px 22px -8px rgba(0,0,0,.5); max-width: 220px; }
.pcd-maptip b { display: block; font-size: .85rem; }

.pcd-corrctrls { display: flex; gap: 12px; flex-wrap: wrap; align-items: flex-end; margin-bottom: 12px; }
.pcd-corrctrls label { display: flex; flex-direction: column; gap: 4px; font-size: .76rem; color: var(--muted); font-weight: 700; }
.pcd-corrctrls select { min-width: 210px; }

.pcd-veil { position: fixed; inset: 0; background: rgba(20,26,37,.14); z-index: 40; }
.pcd-picker { position: absolute; z-index: 41; width: 330px; max-width: 92vw; background: var(--surface); border: 1px solid var(--line-strong); border-radius: var(--radius); box-shadow: 0 18px 48px -14px rgba(20,26,37,.4); overflow: hidden; }
.pcd-pkhead { display: flex; align-items: center; gap: 9px; padding: 11px 13px; border-bottom: 1px solid var(--line); font-weight: 700; font-size: .9rem; }
.pcd-pkback { border: 0; background: var(--surface-2); color: var(--ink); border-radius: var(--pill-sm); width: 26px; height: 26px; cursor: pointer; flex: 0 0 auto; }
.pcd-pksearch { padding: 10px 12px 6px; }
.pcd-pksearch input { width: 100%; border: 1px solid var(--line); border-radius: var(--pill-sm); padding: 8px 11px; font: inherit; background: var(--surface-2); color: var(--ink); }
.pcd-pklist { max-height: 300px; overflow: auto; padding: 4px 6px 8px; }
.pcd-pkgroup { font-size: .68rem; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); font-weight: 700; padding: 9px 8px 3px; }
.pcd-pkitem { display: block; width: 100%; border: 0; background: transparent; text-align: left; padding: 8px 9px; border-radius: var(--pill-sm); cursor: pointer; font: inherit; font-size: .85rem; color: var(--ink); }
.pcd-pkitem:hover { background: var(--surface-2); }
.pcd-pkopt { display: flex; align-items: center; gap: 9px; padding: 7px 9px; border-radius: var(--pill-sm); cursor: pointer; font-size: .85rem; }
.pcd-pkopt:hover { background: var(--surface-2); }
.pcd-pkopt input { width: 16px; height: 16px; accent-color: var(--brand); flex: 0 0 auto; }
.pcd-pkopt span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pcd-pkrange { display: flex; gap: 10px; padding: 6px 12px; }
.pcd-pkrange label { flex: 1; display: flex; flex-direction: column; gap: 3px; font-size: .74rem; color: var(--muted); font-weight: 700; }
.pcd-pkrange input { border: 1px solid var(--line); border-radius: var(--pill-sm); padding: 8px 10px; font: inherit; background: var(--surface-2); color: var(--ink); }
.pcd-pkfoot { display: flex; justify-content: space-between; align-items: center; gap: 10px; padding: 10px 13px; border-top: 1px solid var(--line); background: var(--surface-2); font-size: .78rem; color: var(--muted); }

@media (max-width: 860px) {
	.pcd-grid { grid-template-columns: 1fr; }
	/* narrow: the index becomes a wrapping row above the charts */
	.pcd-body { flex-direction: column; }
	.pcd-nav { position: static; width: 100%; flex-basis: auto; max-height: none;
		flex-direction: row; flex-wrap: wrap; gap: 4px; }
	.pcd-nav button { width: auto; }
	.pcd-navttl { width: 100%; }
}

/* The picture at the head of an event's detail. 16:9 and cropped from the
   centre: organizations upload whatever shape they have, and the modal should
   look the same for all of them. */
.evt-figure {
	margin: 0 0 16px; border-radius: var(--radius-sm); overflow: hidden;
	background: var(--brand-soft); aspect-ratio: 16 / 9;
}
.evt-figure img { inline-size: 100%; block-size: 100%; object-fit: cover; object-position: center; display: block; }

/* Clicking it opens the picture whole (2026-08-31), so it has to look like
   something you can click. */
.evt-figure { cursor: zoom-in; }
.evt-figure:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; }

/* A picture the 16:9 box crops top and bottom follows the pointer: the band on
   screen slides as the cursor moves up and down. The transition is for the way
   BACK — while the pointer is inside, object-position is rewritten per move and
   easing it would lag the cursor. `.4s` only ever plays on mouseleave, because
   that is the one change that is not immediately overwritten. */
/* The cursor stays zoom-in even here: ns-resize would promise dragging, and
   there is none — the picture simply follows the pointer. */
.evt-figure.is-pannable img { transition: object-position .4s var(--ease); }
.evt-figure.is-pannable:hover img { transition: none; }
@media (prefers-reduced-motion: reduce) {
	.evt-figure.is-pannable img { transition: none; }
}

@media (max-width: 640px) {
	/* the date and the picture side by side would leave the title a sliver */
	.evt { flex-wrap: wrap; gap: 14px; }
	.evt-thumb { flex: 0 0 64px; inline-size: 64px; block-size: 64px; }
	.evt-main { flex: 1 1 100%; }
}

/* ----------------------------------------------------------- the curtain -
   The agenda while its programming is still under wraps. The list is empty
   because RCULT's public API answers with nothing until the season is
   launched (see THE CURTAIN in control/ca/public_api.php), so the page needs
   something that reads as "not yet" rather than as "broken": a panel where
   the events would be, saying when they arrive. */
.curtain {
	display: grid; justify-items: center; gap: 16px; text-align: center;
	background: var(--surface-2); border: 1px solid var(--line);
	border-radius: var(--radius); padding: 60px 28px;
}
.curtain svg { width: 34px; height: 34px; color: var(--brand); }
.curtain p {
	margin: 0; max-width: 34ch; font-size: 1.12rem; font-weight: 600;
	line-height: 1.5; color: var(--ink);
}

/* --------------------------------------------------------- agenda map --- */
/* The list/map switch. Two ways of reading the same filtered set, so it sits
   with the results rather than up with the filters. */
.agenda-modes { display: flex; gap: 6px; margin: 0 0 18px; }
/* the switch goes away while the agenda is curtained: there is nothing to
   look at in either mode, and `hidden` alone loses to the flex above */
.agenda-modes[hidden] { display: none; }
.agenda-mode {
	display: inline-flex; align-items: center; gap: 7px;
	background: var(--surface); border: 1px solid var(--line); color: var(--muted);
	border-radius: var(--radius-sm); padding: 7px 14px; font-size: .88rem; font-weight: 600;
	cursor: pointer; transition: background .15s, color .15s, border-color .15s;
}
.agenda-mode:hover { border-color: var(--line-strong); color: var(--ink); }
.agenda-mode.is-on { background: var(--brand-soft); border-color: var(--brand); color: var(--brand-strong); }
.agenda-mode svg { width: 15px; height: 15px; }

.agenda-map {
	block-size: clamp(360px, 60vh, 640px);
	border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden;
	background: var(--brand-soft);
}
/* Why some events are not on the map. Said plainly, because the alternative is
   a visitor deciding the month is empty when it is the venues that lack pins. */
.agenda-map-note { font-size: .84rem; margin: 10px 2px 0; }

/* ---- map mode: the map leads, the list indexes it -------------------------
   Only .is-split changes anything; in list mode the container is a plain block
   and the results keep the full width they always had. */
.agenda-both.is-split {
	display: flex; align-items: flex-start; gap: 16px;
	/* One height for both columns. The map used to stop at 60vh/640px while the
	   list ran to 68vh, so the index hung below the thing it indexes — which
	   read as a mistake. The client asked for them to match, and for the map to
	   be the one that grows. */
	--agenda-split-h: clamp(420px, 68vh, 720px);
}
.agenda-both.is-split .agenda-map {
	flex: 0 0 70%; width: 70%; position: sticky; top: 12px;
	block-size: var(--agenda-split-h);
}
.agenda-both.is-split .agenda-list {
	flex: 1 1 30%; min-width: 0;
	max-height: var(--agenda-split-h); overflow-y: auto;
	display: flex; flex-direction: column; gap: 8px;
}
/* Compact rows: in this mode a row is a label for a pin, not something to read.
   The date block, the thumbnail and the summary all go. */
.agenda-both.is-split .evt { padding: 10px 12px; gap: 10px; cursor: pointer; }
.agenda-both.is-split .evt-date,
.agenda-both.is-split .evt-thumb { display: none; }
/* No "View details" here. The list is a third of the width in this mode and the
   button was taking a column of it, squeezing the title and the venue into a
   strip (reported 2026-09-01). The whole row has been the click target all
   along — it is the same one the pin uses — so the button was only ever saying
   out loud what the cursor already says. The title picks up an underline on
   hover so that reads as an invitation rather than as decoration. */
.agenda-both.is-split .evt .btn { display: none; }
.agenda-both.is-split .evt:hover h3,
.agenda-both.is-split .evt:focus-visible h3 { text-decoration: underline; text-underline-offset: 3px; }
/* The clipped summary. Both lengths are in the markup; only one is ever shown.
   The rule that used to hide the summary here matched `.note`, which is not the
   class the paragraph actually carries — so map mode was showing every event's
   full description. Fixed 2026-08-28 by giving it a class of its own. */
.evt-summary { margin: 8px 0 0; font-size: .88rem; }
.evt-summary [data-role="short"] { display: none; }
.agenda-both.is-split .evt-summary { margin: 4px 0 0; font-size: .8rem; line-height: 1.45; }
.agenda-both.is-split .evt-summary [data-role="full"] { display: none; }
.agenda-both.is-split .evt-summary [data-role="short"] { display: inline; }
.agenda-both.is-split .evt h3 { font-size: .95rem; margin: 0 0 4px; }
.agenda-both.is-split .evt-meta { font-size: .78rem; gap: 8px; }
.agenda-both.is-split .evt .chip { font-size: .68rem; padding: 1px 7px; }
/* The row the pointer picked, and the pin it belongs to, say so together. */
.agenda-both.is-split .evt.is-active {
	border-color: var(--brand); box-shadow: inset 3px 0 0 var(--brand);
}
/* The colour of this event's pin, so a row and a marker can be matched by eye. */
.evt-pin { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 9px; display: inline-block; }

/* Under a tablet the split stops helping: the map would be too narrow to read
   and the list too narrow to scan. Stack them instead. */
@media (max-width: 900px) {
	.agenda-both.is-split { display: block; }
	.agenda-both.is-split .agenda-map {
		width: 100%; position: static; margin-bottom: 14px;
		block-size: clamp(360px, 60vh, 640px);
	}
	.agenda-both.is-split .agenda-list { max-height: none; overflow: visible; }
}

/* ---- venue map inside the event detail ---- */
.evt-venue-map { width: 100%; height: 260px; border-radius: var(--radius-sm); margin-top: 12px; background: var(--surface-2); }
