/* «Новини» — the posts page (home.php) — plan 06 task 5.

   Figma: 1440 `3712:16775` (banner `3977:17457`, filter bar `3712:16822`,
   sorting panel `3850:11663`, grid `3787:15090`), 390 `4434:32886`.
   inventory.md draws no 768 or 1920 frame for this page, so the 1440 values
   start at 1440 — the width they are drawn at — and the type steps through
   tokens.css's own breakpoint modes, exactly as section-title.css documents
   for the same situation.

   Page rhythm, frame to frame:

   | gap                      | 390 | 1440 |
   |--------------------------|-----|------|
   | banner → filter bar      |   0 |    0 |
   | filter bar → grid        |  80 |   80 |
   | grid → «Більше новин»    |  48 |   56 |
   | cards, row gap           |  48 |   40 |
   | cards, column gap        |   — |   24 |

   Design note `4550:25465` («Таби», the new .fig of 22.09.2026):
   «Таби та сортування фіксуються зверху» — the whole filter bar sticks to the
   top of the viewport while the grid scrolls past it. It is `position: sticky`,
   not a script, so it costs no JavaScript and cannot detach from its own
   column. */

/* One column for every section of the page: `--page-gutter`
   (components/container.css, enqueued as `podil-container`). The banner, the
   bar and the grid land on the same two edges as every other page, and the
   ladder is declared in one place — this sheet used to carry its own copy of
   it (plan 06 final review, I2). */

/* ============================================================ Banner

   `3977:17457`: a #F3F4F6 band 1440 wide at x=0 (at 390 the same band is drawn
   as «Background Shape», a 1440-wide rectangle starting at x=−206) — so the
   band is full-bleed and the column inside it is the page gutter. Padding
   0/…/102 at 390 and 0/…/150 at 1440: the breadcrumbs sit on the band's own
   top edge in both frames. */
.news-hero {
	position: relative;
	box-sizing: border-box;
	padding: 0 var(--page-gutter) 102px;

	/* The two frames paint this band differently and the code follows each of
	   them: at 1440 the fill is «Hero» `3977:17457`'s own #F3F4F6, and at 390
	   «Hero Section» `4434:32927` is #FFFFFF with the grey drawn by a child
	   rectangle («Background Shape» `4434:32928`, 1440 wide from x=−206, i.e.
	   full-bleed). Same picture either way; the layer that carries it is the
	   frame's own answer, which is what the spec-diff measures. */
	background: var(--color-base-white);
}

/* --color-neutral-500, the breadcrumb's own colour, measures 4.31:1 on this
   banner's #F3F4F6 — under WCAG AA for 14px text. The same substitution the
   afisha, repertoire and people banners already make for the same pair
   (--color-neutral-600, 6.9:1); designer-questions.md. Found by the final
   axe sweep of plan 06 task 12: axe only resolves this pair once the
   dyslexia face is on, so it had been passing as «incomplete» until now. */
.news-hero .breadcrumbs a {
	color: var(--color-neutral-600);
}

.news-hero::before {
	content: "";
	position: absolute;
	inset: 0;
	background: var(--color-neutral-100);
}

.news-hero__inner {
	position: relative;
}

.news-hero__inner {
	display: flex;
	flex-direction: column;

	/* 390: breadcrumbs end at y 91, the header starts at 193. */
	gap: 102px;
}

/* The trail's `<ol>` is `inline-flex` (breadcrumbs.css, matching the frame's
   own
   hug sizing), so a block `<nav>` around it opens a line box of the page's
   line-height and the 16-high row sits 6 px down inside a 24-high box. A flex
   `<nav>` has no line box, and the trail lands on the band's top edge the way
   `3712:16778` (y 136 = the band's own y) and `4434:32929` draw it. */
.news-hero .breadcrumbs {
	display: flex;
}

/* «Page Title» is «H1/H1 L» here (204/204 at 1440), not the `banner` variant's
   own «H1/H1 M» — the halls banner draws the M step and this page the L one, so
   the type is the only thing the section overrides on the shared component. At
   390 the node is 60/60, which is «H1/H1 M»'s mobile mode. */
.news-hero__header .c-section-title__heading {
	font-size: var(--fs-h1-m);
	line-height: var(--lh-h1-m);
	letter-spacing: var(--ls-h1-m);
}

/* «Page Description» — 284 wide at 390 (`4434:32886`), 244 at 1440
   (`3977:17457`); «S/S text (regular)» in both, which is the component's own
   type. */
.news-hero__header .c-section-title__intro {
	width: 284px;
	max-width: 100%;
}

/* At 150 % text the heading alone is wider than the row, and the pair has to
   fall into two lines rather than push the page sideways (WCAG 1.4.4 / 1.4.10).
   At 100 % nothing wraps, so the frame's own row is untouched. */
.news-hero__header {
	flex-wrap: wrap;
}

/* ============================================================ Filter bar

   `3712:16822` at 1440: 1440×50, a 1px #D0D5DC inside stroke, five equal tabs
   filling 1038 and the 400-wide sorting control at the end. At 390: a 40-high
   strip whose five hug-width tabs add up to 549 and scroll sideways, with the
   sorting control on its own full-width row under it. */
.news-filter {
	position: sticky;
	top: 0;

	/* Above the grid it scrolls over and above the card photos' own stacking,
	   below the site header's mobile menu (site-header.css: 100) and below the
	   accessibility panel. */
	z-index: 20;
	display: flex;
	flex-direction: column;
	box-sizing: border-box;

	/* The tabs are #FFFFFF and the sorting control #F3F4F6; together they cover
	   the bar at 1440, but at 390 the strip is narrower than the viewport while
	   it is scrolled, so the bar carries the page's own ground under them —
	   without it the grid would show through a stuck bar. */
	background: var(--color-base-white);
	box-shadow: inset 0 0 0 1px var(--color-neutral-300);
}

.news-filter__tabs {

	/* `4434:32886`: «Category Tabs» is 549 wide inside a 390 viewport, so the
	   strip scrolls and the page does not (overflow-sweep must stay at 0). */
	overflow-x: auto;
	overscroll-behavior-x: contain;
}

.news-filter__list {
	display: flex;
	margin: 0;
	padding: 0;
	list-style: none;
}

.news-filter__item {
	display: flex;
}

.news-filter__tab {
	display: flex;
	align-items: center;
	justify-content: center;
	box-sizing: border-box;

	/* h:fixed 40 at 390 (`4434:32886`, «Tab All»), h:fill 48 inside the 50 bar
	   at 1440. The label's own box is what grows with the a11y text-size
	   setting, so the height is a minimum, not a cap. */
	min-height: 40px;
	padding: 8px 20px;
	background: var(--color-base-white);
	color: var(--color-neutral-800);

	/* «border=1/0/1/1px #D0D5DC (inside)» on every tab but the first: the rule
	   between two tabs, drawn once. */
	box-shadow: inset 1px 0 0 0 var(--color-neutral-300);
	font-family: var(--font-body);

	/* The 390 nodes carry 16/22 where the mobile mode of «S/S text (semi bold)
	   caps» is 14/18 — a style override the mobile frame kept from its desktop
	   component (designer-questions.md). 16px is `--fs-m-text`'s mobile mode,
	   whose 20px line height is inside the 2px the line-height tolerance
	   allows; the tab's own height is fixed, so the type does not move the box. */
	font-size: var(--fs-m-text);
	font-weight: 600;
	line-height: var(--lh-m-text);
	letter-spacing: var(--ls-m-text);
	text-decoration: none;
	text-transform: uppercase;
	white-space: nowrap;
}

.news-filter__item:first-child .news-filter__tab {
	box-shadow: none;
}

/* «Tab All» in the frames is the selected tab: #272B30 with white type — the
   state is the fill AND the position in the trail (`aria-current="page"`), not
   colour alone. No transition: `interactions` is empty on `3712:16822` and on
   every tab under it, so switching is instant (animations.md's reading of the
   people filter bar, which is the same component pattern). */
.news-filter__item--current .news-filter__tab {
	background: var(--color-neutral-800);
	color: var(--color-base-white);
	box-shadow: none;
}

/* ============================================================ Sorting

   `3712:16822`: 400×48 at 1440, #F3F4F6, a 1px left rule, padding 12/24, the
   icon and the label at the start and «arrow down» at the end. `4434:32886`:
   390×40, padding 12/16. The open panel is `3850:11663` — 401×100, #F3F4F6,
   1px rules on three sides, 8px of bottom padding, two 46-high rows. */
.news-sort {
	position: relative;
	box-sizing: border-box;
}

/* The fill and the left rule belong to «Sort Dropdown» itself, which is the
   summary — the `<details>` around it is a wrapper with no drawing of its own.
      */
.news-sort__summary {
	display: flex;
	align-items: center;
	box-sizing: border-box;
	gap: 8px;
	background: var(--color-neutral-100);
	box-shadow: inset 1px 0 0 0 var(--color-neutral-300);

	/* `4434:32886`: «Sort Dropdown» is h:fixed 40 with pad 12/16 AND a 20-high
	   child — 12 + 20 + 12 is 44, so the frame's own arithmetic does not close.
	   The drawn height wins (it is what sets the rhythm of everything under the
	   bar) and the child centres inside it, which is also where the frame draws
	   it (y 461 = 451 + (40 − 20) / 2). `--font-scale` keeps the box growing
	   with the accessibility widget's text size instead of clipping at 150 %. */
	height: calc(40px * var(--font-scale));
	padding: 12px 16px;
	color: var(--color-neutral-800);
	font-family: var(--font-body);
	font-size: var(--fs-s-text);
	font-weight: 600;
	line-height: var(--lh-s-text);
	letter-spacing: var(--ls-s-text);
	text-transform: uppercase;
	cursor: pointer;
	list-style: none;
}

/* Safari/Chromium's own marker; the design draws «arrow down» instead. */
.news-sort__summary::-webkit-details-marker {
	display: none;
}

.news-sort__icon,
.news-sort__arrow {
	display: flex;
	flex: 0 0 auto;
	align-items: center;
	justify-content: center;
	width: 20px;
	height: 20px;
}

.news-sort__arrow {
	margin-left: auto;
}

.news-sort__icon svg,
.news-sort__arrow svg {
	width: 20px;
	height: 20px;
}

.news-sort__options {
	position: absolute;
	top: 100%;
	right: 0;
	z-index: 1;
	box-sizing: border-box;
	width: 100%;
	margin: 0;
	padding: 0 0 8px;
	background: var(--color-neutral-100);

	/* «border=0/1/1/1px» — the row above it is the control itself. */
	box-shadow:
		inset -1px 0 0 0 var(--color-neutral-300),
		inset 1px 0 0 0 var(--color-neutral-300),
		inset 0 -1px 0 0 var(--color-neutral-300);
	list-style: none;
}

.news-sort__link {
	display: flex;
	align-items: center;
	box-sizing: border-box;
	gap: 8px;
	padding: 12px 16px;
	color: var(--color-neutral-900);
	font-family: var(--font-body);
	font-size: var(--fs-s-text);
	font-weight: 600;
	line-height: var(--lh-s-text);
	letter-spacing: var(--ls-s-text);
	text-decoration: none;
	text-transform: uppercase;
}

/* «Checkbox Unchecked» / «Checkbox Checked» `3850:11663`: 16×16, radius 2. The
   unchecked box's stroke in the design is #C3C6CA, which is not in this
   design system's palette (datamapping §… lists eleven greys and that is not
   one of them), so it is the nearest token — `--color-neutral-300` #D0D5DC —
   and a line in designer-questions.md. The box is decorative
   (`aria-hidden`): the chosen order is carried by `aria-current` and by the
   words, never by the box alone. */
.news-sort__box {
	display: flex;
	flex: 0 0 auto;
	align-items: center;
	justify-content: center;
	box-sizing: border-box;
	width: 16px;
	height: 16px;
	border-radius: 2px;
	box-shadow: inset 0 0 0 1px var(--color-neutral-300);
}

.news-sort__link--current .news-sort__box {
	background: var(--color-neutral-900);
	box-shadow: inset 0 0 0 1px var(--color-neutral-900);
}

.news-sort__link--current .news-sort__box svg {
	width: 12px;
	height: 12px;
	color: var(--color-base-white);
}

.news-sort__link--current .news-sort__box svg path,
.news-sort__link--current .news-sort__box svg rect {
	fill: currentcolor;
}

/* ============================================================ Grid

   `3787:15090`: 1328 wide, three 427 columns with 24 between them, 40 between
   rows. `4434:32886`: one 358 column, 48 between rows. 80 under the filter bar
   in both frames. */
.news-main {
	box-sizing: border-box;
	padding: 80px var(--page-gutter) 0;
}

.news-grid {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: 48px;
	margin: 0;
	padding: 0;
	list-style: none;
}

.news-grid__item {
	display: flex;
	min-width: 0;
}

.news-grid__item > * {
	width: 100%;
}

/* A `tabindex="-1"` is put on the first card of a loaded batch so the focus can
   land on it (news.js); it is a scroll target, not a control, so it keeps no
   ring of its own beyond the browser's. */
.news-grid__item:focus-visible {
	outline: 2px solid var(--color-primary-700);
	outline-offset: 4px;
}

.news-empty {
	margin: 0;
	color: var(--color-neutral-800);
	font-family: var(--font-body);
	font-size: var(--fs-s-text);
	line-height: var(--lh-s-text);
}

.news-more {
	margin-top: 48px;
}

/* ============================================================= 768+ */

@media (min-width: 768px) {

	.news-hero__header .c-section-title__intro {

		/* No 768 frame: the 390 measurement holds until the width that has one. */
		width: 284px;
	}

	.news-filter__tabs {
		flex: 1 1 auto;
		min-width: 0;
	}

	.news-filter__list {
		width: 100%;
	}

	.news-filter__item {
		flex: 1 1 0;
	}

	/* `3712:16822`: the five tabs fill 1038 in equal parts, 48 high, pad 12/20,
	   «S/S text (semi bold) caps». */
	.news-filter__tab {
		width: 100%;
		min-height: 48px;
		padding: 12px 20px;
		font-size: var(--fs-s-text);
		line-height: var(--lh-s-text);
		letter-spacing: var(--ls-s-text);
	}

	.news-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: 40px 24px;
	}
}

/* ============================================================ 1440+ */

@media (min-width: 1440px) {

	.news-hero {

		/* At 1440 the band's fill is the section's own (`3977:17457`), so the
		   full-bleed child layer is dropped. */
		background: var(--color-neutral-100);

		/* `3977:17457` reports pad 0/358/150/56, but the 358 is not a padding the
		   design set: it is what is left of the row after the 1026-wide «Content
		   Container», which is itself exactly that column's own content in Kilok
		   (742 + 40 + 244). Reproducing it as a real padding would cap the row at
		   1026 and fold the description onto a second line, because the substitute
		   font sets the heading 60 px wider. So the band keeps the page's gutter on
		   both sides — the column still starts on the grid's own left edge, which
		   is what the eye and the container rule care about — and the reported
		   padding stays a residual in task-5-report.md. */
		padding-bottom: 150px;
	}

	.news-hero::before {
		content: none;
	}

	/* `3977:17456`: «Content Container» VERTICAL 98, w:fixed 1026 — which is
	   exactly its own content in Kilok (742 + 40 + 244). The substitute font
	   sets «НОВИНИ» 60 px wider, so the column is its content's width capped by
	   the row: the frame's number where the frame's font holds, and no page
	   overflow where it does not. */
	.news-hero__inner {
		gap: 98px;
		width: fit-content;
		max-width: 100%;
	}

	.news-hero__header .c-section-title__heading {
		font-size: var(--fs-h1-l);
		line-height: var(--lh-h1-l);
		letter-spacing: var(--ls-h1-l);
	}

	.news-hero__header .c-section-title__intro {

		/* `3977:17457`: «Page Description» w:fixed 244, at the row's end. */
		flex: 0 0 244px;
		width: 244px;
	}

	/* `3712:16822`: one 50-high row — the five tabs and the 400-wide sorting
	   control side by side. The 1 px of padding is the bar's own inside stroke:
	   it is drawn with `box-shadow: inset`, which takes no space, so the 1440×50
	   bar holds a 1438×48 row only if the space is reserved (tabs 1038 + sorting
	   400 = 1438, and 48 + 2 = 50). */
	.news-filter {
		flex-direction: row;
		justify-content: space-between;
		padding: 1px;
	}

	.news-sort {
		flex: 0 0 400px;
		width: 400px;
	}

	.news-sort__summary {

		/* `3712:16822`: 48 high, pad 12/24, the 23-high label centred at 556.5. */
		height: calc(48px * var(--font-scale));
		padding: 12px 24px;
	}

	.news-sort__options {

		/* `3850:11663` is 401 wide against the control's 400: the extra pixel is
		   the panel's own left stroke, which the control's stroke covers. */
		width: 401px;
	}

	.news-grid {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}

	.news-more {

		/* `3787:15090`: «News Grid Section» VERTICAL 56. */
		margin-top: 56px;
	}
}

/* ======================================================== Forced colours

   Every edge on this page is a `box-shadow: inset` (the project's convention
   for a Figma inside stroke), and Chromium drops author box-shadows under
   forced-colors — without this the bar, the tabs, the sorting control and the
   checkbox have no boundary at all. `outline` never changes the box
   (base.css's own reasoning). */
@media (forced-colors: active) {

	.news-filter,
	.news-sort,
	.news-sort__box,
	.news-sort__options {
		outline: 1px solid CanvasText;
		outline-offset: -1px;
	}

	.news-filter__item:not(:first-child) .news-filter__tab {
		border-left: 1px solid CanvasText;
	}

	/* The selected tab is a fill, which forced-colors flattens: the words keep
	   their own mark so the state survives. */
	.news-filter__item--current .news-filter__tab {
		outline: 2px solid CanvasText;
		outline-offset: -2px;
	}
}
