/* ============================================================================
   Hayotiy Til — design system
   Ported from the approved til.uz direction 2a (Claude Design): Onest for UI,
   Literata for editorial headings, warm paper ground, single red accent.

   Accessibility targets follow TZ 4.1.6 (WCAG 2.1 AA): contrast, 44px touch
   targets, visible focus, keyboard navigation, and layout that survives 200%
   browser zoom because every size is in rem/em or clamp().
   ========================================================================= */

:root {
  /* ground & ink */
  --paper:        #FAF6EF;
  --paper-alt:    #F3ECDF;
  --paper-warm:   #EFE7DA;
  --white:        #ffffff;
  --ink:          #2C2622;
  --ink-soft:     #4A4038;
  --muted:        #5E5346;   /* AA on --paper */
  --faint:        #6E6355;   /* AA on --paper */
  --line:         #E7DDD0;
  --line-strong:  #E0D6C8;
  --sand:         #C9BBA8;

  /* accent */
  --accent:       #FB483B;   /* HAYOT CORAL */
  --accent-deep:  #A83A2C;   /* AA on --paper for small text */
  --accent-wash:  #FBEEE9;

  /* semantic */
  --ok:           #1E7D48;
  --warn:         #8A6A1F;
  --ok-wash:      #E8F3EC;
  --ok-line:      #BEDFC9;
  --ok-ink:       #14532D;
  --warn-wash:    #F6EFDC;
  --err:          #B3261E;
  --err-wash:     #FBE9E7;
  --err-line:     #F3C6C0;
  --err-ink:      #8B1D13;

  /* gold — the «recommended» mark, kept apart from the coral accent */
  --gold:         #D9A23A;
  --gold-wash:    #FBF1DC;
  --gold-ink:     #2C2622;   /* text on --gold: 8:1 */

  /* text on the coral, and the coral under the pointer */
  --on-accent:    #ffffff;
  --accent-hover: #E23B2E;

  /* The dark band — the footer, the dark card — stays dark in both themes;
     it is not the ink inverted, so it gets colours of its own. */
  --band:             #2C2622;
  --band-ink:         #CFC5B8;
  --band-ink-strong:  #F3EADD;
  --band-faint:       #9A8E7F;

  --popover-shadow: 0 8px 24px rgba(44, 38, 34, .12);
  --hairline-inset: inset 0 0 0 1px rgba(44, 38, 34, .06);
  --rule-diamond:   #C9A38F;

  /* the dialect map */
  --map-stroke:       #ffffff;
  --map-mix:          #F3ECE2;
  --map-halo:         rgba(255, 255, 255, .9);
  --map-plain-stroke: #B9AA96;

  --radius-sm: 8px;
  --radius:    12px;
  --radius-lg: 16px;
  --shadow-sm: 0 1px 3px rgba(76, 54, 32, .06);
  --shadow:    0 10px 30px rgba(76, 54, 32, .08);
  --shadow-lg: 0 12px 32px rgba(76, 54, 32, .10);

  --wrap: 1160px;
  --font-ui: Montserrat, Onest, system-ui, -apple-system, "Segoe UI", sans-serif;
  /* Okina carries U+02BB alone — Literata draws it with no advance width,
     so it lands on the preceding letter. See fonts.css. */
  /* One family across the portal, as the brand book asks. The heading face
     used to be Literata; it survives as a reading choice in the tale reader
     (--font-reading-serif) and nowhere else, so its okina patch stays too. */
  --font-serif: Montserrat, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-reading-serif: Literata, Okina, Georgia, "Noto Serif", "Times New Roman", serif;
}

/* ---- Dark theme -----------------------------------------------------------
   The same warm paper, by lamplight: a brown-black ground rather than a cold
   grey, ink the colour of the paper it replaces, and the coral kept as the
   one accent. Every pair below holds WCAG AA on its ground: muted text 8:1 on
   --paper, faint 6:1, the link coral 7:1.

   `data-theme` is set before the first paint by the snippet in base.html —
   the reader's stored choice, else the system's — so there is no flash of
   the light page. A tale opened in the reader's own sepia or light theme
   keeps it: `data-reader-theme` takes the page over, as it always did. */
:root[data-theme="dark"]:not([data-reader-theme]) {
  --paper:        #161311;
  --paper-alt:    #1D1916;
  --paper-warm:   #25201C;
  --white:        #201C19;   /* the card surface: a step up from the page */
  --ink:          #EDE6DC;
  --ink-soft:     #D8CFC3;
  --muted:        #AFA59A;
  --faint:        #9D9388;
  --line:         #2F2925;
  --line-strong:  #3D3631;
  --sand:         #5F564E;

  --accent:       #FB5446;
  --accent-deep:  #FF8F84;
  --accent-wash:  #3A221E;
  --accent-hover: #FF6A5D;

  --ok:           #6FCF97;
  --warn:         #E3B75E;
  --ok-wash:      #173324;
  --ok-line:      #2A5A3E;
  --ok-ink:       #A7E8C2;
  --warn-wash:    #33290F;
  --err:          #FF8F84;
  --err-wash:     #3A1D1A;
  --err-line:     #6B2C26;
  --err-ink:      #FFC2BB;

  /* the band sinks below the page instead of standing out of it */
  --band:         #0E0C0B;

  --gold:         #E0B04F;
  --gold-wash:    #2E2414;
  --gold-ink:     #1A1408;

  --shadow-sm:      0 1px 2px rgba(0, 0, 0, .5);
  --shadow:         0 10px 30px rgba(0, 0, 0, .5);
  --shadow-lg:      0 14px 36px rgba(0, 0, 0, .55);
  --popover-shadow: 0 10px 28px rgba(0, 0, 0, .55);
  --hairline-inset: inset 0 0 0 1px rgba(255, 255, 255, .04);
  --rule-diamond:   #8A6E60;

  --map-stroke:       #161311;
  --map-mix:          #25201C;
  --map-halo:         rgba(22, 19, 17, .9);
  --map-plain-stroke: #5F564E;

  color-scheme: dark;
}

/* The header lockup: grey lettering on paper, white on the dark ground.
   Same artwork, the variant the footer already uses. Scoped under .brand so
   these outrank `.brand__logo { display: block }` further down. */
.brand .brand__logo--dark { display: none; }
:root[data-theme="dark"]:not([data-reader-theme]) .brand .brand__logo--light,
:root[data-reader-theme="dark"] .brand .brand__logo--light { display: none; }
:root[data-theme="dark"]:not([data-reader-theme]) .brand .brand__logo--dark,
:root[data-reader-theme="dark"] .brand .brand__logo--dark { display: block; }

/* Pictures drawn on paper — the tale covers — are dimmed a little so they do
   not glare out of the dark page; hovering brings them up to full. */
:root[data-theme="dark"]:not([data-reader-theme]) .tale-card__cover img,
:root[data-theme="dark"]:not([data-reader-theme]) .tale-hero img {
  filter: brightness(.88);
  transition: opacity .5s ease, filter .2s ease;   /* keeps the covers' fade-in */
}
:root[data-theme="dark"]:not([data-reader-theme]) .tale-card:hover .tale-card__cover img { filter: none; }

/* Theme switch: a moon on the light page, a sun on the dark one. */
.theme-toggle { cursor: pointer; }
.theme-toggle svg { display: block; }
.theme-toggle .theme-toggle__sun { display: none; }
:root[data-theme="dark"]:not([data-reader-theme]) .theme-toggle .theme-toggle__sun,
:root[data-reader-theme="dark"] .theme-toggle .theme-toggle__sun { display: block; }
:root[data-theme="dark"]:not([data-reader-theme]) .theme-toggle .theme-toggle__moon,
:root[data-reader-theme="dark"] .theme-toggle .theme-toggle__moon { display: none; }
/* A theme change is instant. It used to fade over .25s, which read as the
   switch lagging behind the click — and animating every element on a long
   page is real work on a slow device. For the one frame of the switch the
   elements' own transitions (hover colours on cards and buttons) are off too,
   so nothing drifts into place after the page has already changed. */
html.theme-switching, html.theme-switching * { transition: none !important; }

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

/* The scrollbar's column is reserved whether or not there is one to draw.
   Otherwise a page that fits the window and one that does not centre their
   content 15px apart, and going between them the whole page lurches
   sideways. */
html { -webkit-text-size-adjust: 100%; scrollbar-gutter: stable; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: 1rem;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

a { color: var(--accent-deep); text-decoration: none; }
a:hover { text-decoration: underline; }

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

img { max-width: 100%; height: auto; }

h1, h2, h3, h4 {
  font-family: var(--font-serif);
  font-weight: 600;
  line-height: 1.2;
  margin: 0 0 .5em;
  letter-spacing: -.01em;
  text-wrap: balance;
}
h1 { font-size: clamp(1.75rem, 4vw, 2.6rem); font-weight: 500; }
h2 { font-size: clamp(1.35rem, 2.6vw, 1.875rem); }
h3 { font-size: clamp(1.1rem, 2vw, 1.3rem); }
p  { margin: 0 0 1em; text-wrap: pretty; }

.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 1.5rem; }
.wrap--narrow { max-width: 800px; }
.wrap--reading { max-width: 720px; }

/* skip link — keyboard navigation, TZ 4.1.6 */
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--ink); color: var(--paper);
  padding: .75rem 1.25rem; border-radius: 0 0 var(--radius-sm) 0;
}
.skip-link:focus { left: 0; }

/* ---------------------------------------------------------------- top strip */
.topbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap;
  padding: .5rem 0;
  border-bottom: 1px solid var(--line);
  font-size: .78rem;
  color: var(--muted);
}
.topbar__links { display: flex; align-items: center; gap: 1.125rem; flex-wrap: wrap; }
.topbar a { color: var(--muted); }

/* Language and script switch (TZ 4.1.2 — must stay permanently reachable),
   a dropdown. Rendered twice: in the top strip on wide screens, in the brand
   row on phones; exactly one is displayed, so only one reaches the
   accessibility tree. */
.lang-menu { position: relative; margin-left: .5rem; }
.lang-menu > summary {
  list-style: none; cursor: pointer; display: inline-flex; align-items: center; gap: .25rem;
  min-height: 28px; padding: .125rem .375rem; border-radius: 6px;
  color: var(--ink); font-size: .82rem; font-weight: 600;
}
.lang-menu > summary::-webkit-details-marker { display: none; }
.lang-menu > summary:hover, .lang-menu[open] > summary { background: var(--paper-warm); }
.lang-menu__chev { color: var(--muted); transition: transform .15s ease; }
.lang-menu[open] .lang-menu__chev { transform: rotate(180deg); }
.lang-menu__list {
  position: absolute; right: 0; top: calc(100% + 4px); z-index: 30;
  list-style: none; margin: 0; padding: .25rem; background: var(--white);
  border: 1px solid var(--line); border-radius: 8px; box-shadow: var(--popover-shadow);
}
.lang-menu__list a {
  display: block; padding: .3rem .75rem; border-radius: 5px; color: var(--muted);
  font-size: .82rem; text-align: center;
}
.lang-menu__list a:hover { background: var(--paper-warm); color: var(--ink); text-decoration: none; }
.lang-menu__list a[aria-current="true"] { color: var(--ink); font-weight: 600; }
/* The narrow copy is hidden by default and only shown at phone widths; this
   must sit AFTER the base rule to win on source order. */
.lang-menu--narrow { display: none; }

/* -------------------------------------------------------------------- header */
/* The header is one layer above the page. Its dropdowns (Folklor, language)
   hang over the hero, and on phones the nav row scrolls sideways — iOS makes
   that row a stacking context of its own, which trapped the Folklor panel's
   z-index and let the hero's heading paint over it. Lifting the whole header
   keeps every panel in it on top, wherever it is trapped. */
.masthead { border-bottom: 1px solid var(--line); background: var(--paper);
            position: relative; z-index: 40; }
.masthead__inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1.5rem; padding: 1rem 0;
}
/* The lockup is one image from the brand pack. Sized by height so the heart
   and wordmark come out the same in the Uzbek and the (wider) Russian
   version; the guideline's clear space is 1× the coral dot, which the
   masthead's padding more than covers. */
.brand { display: inline-flex; align-items: center; flex: none; }
.brand__logo { height: 76px; width: auto; display: block; }
.brand:hover { text-decoration: none; }

.nav { display: flex; align-items: center; gap: 1.5rem; flex-wrap: wrap;
       margin-left: auto; }
.nav a {
  color: var(--ink); font-size: .95rem; font-weight: 500;
  padding: .5rem 0; min-height: 44px; display: inline-flex; align-items: center;
}
.nav a[aria-current="page"] { box-shadow: inset 0 -2px 0 var(--accent); }

.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border: 1px solid var(--line-strong);
  border-radius: 99px; color: var(--ink); background: transparent;
}
.icon-btn:hover { text-decoration: none; border-color: var(--sand); }

/* Folklor: a section with sub-sections, as a dropdown in the nav row. */
.nav-menu { position: relative; }
.nav-menu > summary {
  list-style: none; cursor: pointer; display: inline-flex; align-items: center; gap: .3rem;
  color: var(--ink); font-size: .95rem; font-weight: 500; padding: .5rem 0; min-height: 44px;
  white-space: nowrap;
}
.nav-menu > summary::-webkit-details-marker { display: none; }
.nav-menu > summary[aria-current="page"] { box-shadow: inset 0 -2px 0 var(--accent); }
.nav-menu__chev { color: var(--muted); transition: transform .15s ease; }
.nav-menu[open] .nav-menu__chev { transform: rotate(180deg); }
.nav-menu__list {
  position: absolute; left: -.75rem; top: calc(100% + 2px); z-index: 30; min-width: 13rem;
  list-style: none; margin: 0; padding: .375rem; background: var(--white);
  border: 1px solid var(--line); border-radius: 10px; box-shadow: var(--popover-shadow);
}
.nav-menu__list a, .nav-menu__list span {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  padding: .5rem .75rem; border-radius: 6px; font-size: .92rem; min-height: 0; white-space: nowrap;
}
.nav-menu__list a { color: var(--ink); }
.nav-menu__list a:hover { background: var(--paper-warm); text-decoration: none; }
.nav-menu__list a[aria-current="page"] { font-weight: 600; box-shadow: none; background: var(--paper-warm); }
.nav-menu__list span { color: var(--faint); cursor: default; }
.nav-menu__list em { font-style: normal; font-size: .72rem; text-transform: uppercase; letter-spacing: .06em;
                     color: var(--faint); background: var(--paper-warm); padding: .1rem .4rem; border-radius: 4px; }
.nav-toggle { display: none; }

/* --------------------------------------------------------------- components */
.eyebrow {
  font-size: .72rem; letter-spacing: .16em; text-transform: uppercase;
  font-weight: 700; color: var(--accent-deep); margin: 0 0 .5rem;
}

/* The name of a source, wherever one is credited. A dictionary title is a
   proper name and reads as one — the uppercase treatment of .eyebrow turns a
   50-character title into shouting.

   Link-coloured, so it is legible as the way through to the dictionary, but
   kept light and unadorned: it sits between a headword and a definition and
   should not compete with either. */
.source-name {
  font-size: .8125rem; font-weight: 400; letter-spacing: 0;
  color: var(--accent-deep); text-transform: none; margin: 0;
  text-decoration: none;
}
a.source-name:hover, a.source-name:focus-visible { color: var(--accent); }

.section-head {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 1rem; border-bottom: 2px solid var(--ink);
  padding-bottom: .625rem; margin: 0 0 1.375rem;
}
.section-head h2 { margin: 0; }
.section-head a { font-size: .875rem; font-weight: 500; }

.card {
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 1.25rem 1.375rem;
  box-shadow: var(--shadow-sm);
}
.card--flat { box-shadow: none; }
.card--dark { background: var(--band); color: var(--band-ink-strong); border-color: var(--band); }
.card--dark a { color: var(--band-ink-strong); }

.grid { display: grid; gap: 1.125rem; }
/* Without this a single wide child (a map, a table, a long word)
   sets a min-content floor and pushes the whole grid off screen. */
.grid > * { min-width: 0; }
.grid--2 { grid-template-columns: repeat(2, 1fr); }
.grid--3 { grid-template-columns: repeat(3, 1fr); }
.grid--4 { grid-template-columns: repeat(4, 1fr); }
.grid--cards { grid-template-columns: repeat(4, 1fr); }
.grid--sidebar { grid-template-columns: 1.55fr 1fr; }

.pill {
  display: inline-flex; align-items: center; gap: .35rem;
  background: var(--white); border: 1px solid var(--line-strong);
  border-radius: 99px; padding: .3rem .8rem; font-size: .8rem;
  color: var(--ink); text-decoration: none; min-height: 32px;
}
.pill:hover { text-decoration: none; border-color: var(--sand); }
.pill[aria-pressed="true"], .pill--active {
  background: var(--ink); color: var(--paper); border-color: var(--ink);
}

.badge {
  display: inline-block; font-size: .68rem; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase;
  border-radius: 99px; padding: .2rem .625rem;
  background: var(--accent-wash); color: var(--accent-deep);
}
.badge--muted { background: var(--paper-warm); color: var(--faint); }
/* A language tag sits beside a headword several times its size. Its row is
   baseline-aligned — the Cyrillic pair beside the heading needs that — but a
   pill has a box, and putting its small text on the heading's baseline drops
   the box well below the word's middle. It centres on the text instead:
   align-self where the row is flex, vertical-align where it is inline. */
.badge--lang { align-self: center; vertical-align: middle; }

/* Sources capitalise headwords however they please — mehr, MEHR, Меҳр, love²,
   SALOMNOMA — so a page of results reads as though the case meant something.
   It does not, so it is set once here rather than edited into 263 000 rows. */
.headword { text-transform: uppercase; }
.badge--ok { background: var(--ok-wash); color: var(--ok); }
.badge--warn { background: var(--warn-wash); color: var(--warn); }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  font-family: var(--font-ui); font-weight: 600; font-size: .95rem;
  padding: .75rem 1.375rem; border-radius: 9px; border: 1px solid transparent;
  cursor: pointer; min-height: 44px; text-decoration: none;
}
.btn:hover { text-decoration: none; }
.btn--primary { background: var(--accent); color: var(--on-accent); }
.btn--primary:hover { background: var(--accent-hover); }
.btn--ghost { border-color: var(--sand); background: transparent; color: var(--ink); }
.btn--ghost:hover { border-color: var(--ink); }
.btn--sm { padding: .5rem 1rem; min-height: 38px; font-size: .875rem; }

/* search box (the 2a hero input group) */
/* The hero stagger animates siblings with fill-mode: both, which keeps each of
   them in a stacking context for good — so the decorative rule *after* the form
   painted over the open dropdown. The form has to win that comparison itself;
   a z-index on the panel inside it is trapped and cannot. */
.searchbox { position: relative; z-index: 30; }
/* the field on a word page, above the article; matches the width it has on
   the results page so the reader meets the same box on both */
.word-search { max-width: 44rem; margin-bottom: 1.5rem; }
.searchbox__field { position: relative; }
.hero-decor { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
/* Centred on the screen edge, level with the search box; the layer clips the
   outer half. On the home page it runs on past the hero, down beside the
   first row of cards, which sit above it (.hero-row below). */
.home-decor { bottom: -300px; }
.hero-ornament { position: absolute; top: 50%; width: 820px; height: auto; max-width: none;
                 opacity: .2; transform: translateY(-50%); }
.hero-ornament--left { left: -500px; }
.hero-ornament--right { right: -500px; }
/* The pale ornament reads as a watermark on paper and as a glare on the dark
   page; darkened, it sinks back into the ground. */
:root[data-theme="dark"]:not([data-reader-theme]) .hero-ornament { filter: brightness(.45) saturate(.85); }
@media (max-width: 1100px) {
  .hero-ornament { width: 620px; opacity: .16; }
  .hero-ornament--left { left: -430px; }
  .hero-ornament--right { right: -430px; }
}
@media (max-width: 640px) {
  /* On a phone only a sliver at each edge, so it frames the text and never
     sits under it. */
  .hero-ornament { width: 420px; opacity: .14; top: 38%; }
  .hero-ornament--left { left: -350px; }
  .hero-ornament--right { right: -350px; }
}
.searchbox__group {
  display: flex; background: var(--white); border: 1px solid var(--line-strong);
  border-radius: 14px; box-shadow: var(--shadow);
  transition: border-radius .12s ease, border-color .12s ease, box-shadow .12s ease;
}
/* One focus ring, drawn by the wrapper along its own corners. The input
   itself paints none: a browser ring on the inner field sits a few pixels
   inside the wrapper's border with a different radius, and the two frames
   read as a mistake. The ring is a shadow rather than an outline so it
   follows the 14px radius and does not clip against the neighbours. */
.searchbox__group:focus-within {
  border-color: var(--accent);
  box-shadow: var(--shadow), 0 0 0 3px var(--accent-wash);
}
.searchbox input[type="search"], .searchbox input[type="text"] {
  flex: 1; border: 0; outline: 0; background: transparent;
  padding: 1rem .5rem 1rem 1.25rem; font-size: 1.0625rem;
  font-family: var(--font-ui); color: var(--ink); min-width: 0;
}
.searchbox input[type="search"]::-webkit-search-cancel-button { display: none; }
.searchbox__submit { margin: .5rem; border-radius: 9px; }
.searchbox__submit-icon { display: none; }
/* The back arrow only exists in the mobile overlay below. */
.searchbox__back {
  display: none; place-items: center; width: 44px; flex: 0 0 44px;
  border: 0; background: none; color: var(--muted); cursor: pointer;
  padding: 0; margin-left: .25rem; border-radius: 50%;
}
.searchbox__back:hover, .searchbox__back:focus-visible { color: var(--ink); }

/* The panel is joined to the input rather than floating below it: the two
   share an edge, so the list reads as an extension of the field. */
.suggestions {
  position: absolute; left: 0; right: 0; top: 100%;
  background: var(--white); border: 1px solid var(--line-strong);
  border-top: 0; border-radius: 0 0 14px 14px;
  box-shadow: var(--shadow-lg);
  list-style: none; margin: 0; padding: .25rem; text-align: left;
  max-height: min(58vh, 24rem); overflow-y: auto;
  overscroll-behavior: contain;
}
/* With the list open the field is the top of a taller panel: the ring would
   stop dead at the seam, so the panel's border takes the accent instead. */
.searchbox.is-suggesting .searchbox__group,
.searchbox.is-suggesting .searchbox__group:focus-within {
  border-radius: 14px 14px 0 0; box-shadow: none; border-color: var(--accent);
}
.searchbox.is-suggesting .suggestions { border-color: var(--accent); }
.suggestions li { margin: 0; }
.suggestions button {
  display: block; width: 100%; text-align: left; background: none; border: 0;
  padding: .75rem .875rem; font: inherit; color: var(--ink);
  border-radius: var(--radius-sm); cursor: pointer;
}
/* The highlighted row is the one the script marks, not the one under the
   pointer: the focus stays in the field, and hovering merely moves the mark. */
.suggestions button[aria-selected="true"] { background: var(--paper); }
.suggestions button b { font-weight: 600; }
/* A suggestion that is not an Uzbek word names its language, small and
   after the word, as the card's badge does. Not uppercased with the word. */
.suggestions__lang {
  margin-left: .625rem; font-size: .75rem; font-weight: 400;
  text-transform: none; letter-spacing: 0; color: var(--faint);
}
/* A near miss — the word the reader may have meant rather than one they
   began — is marked so as not to pass for a completion. */
.suggestions button.is-near::before {
  content: "≈"; display: inline-block; width: 1.1em; margin-left: -.1em;
  color: var(--faint); font-weight: 400;
}
.suggestions[hidden] { display: none; }

/* «Balki: …» above results that matched only loosely. */
.did-you-mean { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; margin-top: .75rem; }

/* What the search understands, shown in the mobile panel while it is still
   empty. It answers the question a blank field invites — what can I type? —
   and costs nothing on the landing page, where it is not rendered. */
.searchbox__help { display: none; padding: 1.125rem 1.25rem 1.5rem; }
.searchbox__help-head {
  margin: 0; font-size: .72rem; letter-spacing: .14em; text-transform: uppercase;
  font-weight: 700; color: var(--faint);
}
.searchbox__help ul {
  list-style: none; margin: .875rem 0 0; padding: 0; display: grid; gap: .75rem;
}
.searchbox__help li {
  margin: 0; font-size: .875rem; line-height: 1.45; color: var(--muted);
}
/* The examples are set apart by colour alone — at this size a bolder weight
   made three short lines look like three headings. */
.searchbox__help b { font-weight: inherit; color: var(--ink); }

/* --- mobile: focusing the field takes over the screen ---------------------
   On a phone the box sits halfway down the page, so an open keyboard leaves
   the list a few cramped lines between hero and keyboard. Focusing gives the
   search the whole viewport, the way a native search does. */

@media (max-width: 640px) {
  body.is-searching { overflow: hidden; }

  /* The whole screen, like a native search screen: while you are searching,
     searching is all there is. Nothing of the page shows through, so there is
     nothing to dim and no way to tap "outside" — the back arrow and Escape are
     the ways out. */
  .searchbox.is-open {
    position: fixed; inset: 0; z-index: 120; overflow-y: auto;
    margin: 0; padding: .5rem .625rem .625rem; background: var(--white);
    animation: search-lift .22s cubic-bezier(.2, .7, .3, 1);
    /* The hero centres its children; the panel is its own context and reads
       as a column of text, so it sets alignment rather than inheriting it. */
    text-align: left;
  }
  .searchbox.is-open .searchbox__group {
    border-radius: var(--radius); border-color: var(--line-strong);
    box-shadow: none;
  }
  .searchbox.is-open .searchbox__back { display: grid; }
  .searchbox.is-open input[type="search"] { padding: .8125rem .5rem; }

  /* The label gives way to the magnifier — the same one the masthead uses.
     At this width the field needs the room, and the icon says enough. */
  .searchbox.is-open .searchbox__submit {
    margin: .3125rem; padding: 0; width: 42px; min-height: 42px;
    display: grid; place-items: center;
  }
  .searchbox.is-open .searchbox__submit-label { position: absolute; left: -9999px; }
  .searchbox.is-open .searchbox__submit-icon { display: block; }

  /* The list stays joined to the field, which is now inset from the edges. */
  .searchbox.is-open .suggestions {
    border-color: var(--line-strong);
    border-radius: 0 0 var(--radius) var(--radius);
    /* Fills what is left above the keyboard instead of a fixed cap. */
    max-height: calc(100dvh - 6rem);
  }
  /* No ring in the panel: taking the whole screen is the focus indication,
     and the accent border would sit alone on an otherwise plain sheet. */
  .searchbox.is-open .searchbox__group:focus-within {
    border-color: var(--line-strong); box-shadow: none;
  }
  .searchbox.is-open.is-suggesting .searchbox__group,
  .searchbox.is-open.is-suggesting .searchbox__group:focus-within {
    border-radius: var(--radius) var(--radius) 0 0;
    border-color: var(--line-strong);
  }

  .searchbox.is-open:not(.is-suggesting) .searchbox__help { display: block; }
}

@keyframes search-lift { from { opacity: 0; transform: translateY(-8px); } }

/* --- skeletons -------------------------------------------------------------
   Used only where content really is fetched after the page has painted:
   the autocomplete list and the reader's word popup. Server-rendered pages
   (word cards, search results) arrive complete and must not be faked. */
.skeleton {
  background: linear-gradient(90deg,
              var(--line) 25%, var(--paper-warm) 37%, var(--line) 63%);
  background-size: 400% 100%;
  border-radius: 4px;
  animation: skeleton-shimmer 1.4s ease-in-out infinite;
}
@keyframes skeleton-shimmer {
  from { background-position: 100% 50%; }
  to   { background-position: 0 50%; }
}
.suggestions__loading { padding: .5rem .875rem; display: grid; gap: .5rem; }
.suggestions__loading .skeleton { height: 1rem; }
.suggestions__loading .skeleton:nth-child(1) { width: 72%; }
.suggestions__loading .skeleton:nth-child(2) { width: 54%; }
.suggestions__loading .skeleton:nth-child(3) { width: 63%; }

@media (prefers-reduced-motion: reduce) {
  .skeleton { animation: none; background: var(--line); }
}

/* ornamental divider from the 2a hero */
.rule { display: flex; justify-content: center; align-items: center; gap: .875rem;
        margin: 2rem 0; }
.rule i { flex: 1; max-width: 140px; height: 1px; background: var(--line-strong); }
.rule b { width: 6px; height: 6px; border: 1.2px solid var(--rule-diamond); transform: rotate(45deg); }
.rule em { width: 8px; height: 8px; background: var(--accent); opacity: .75;
           transform: rotate(45deg); }

.band { background: var(--paper-alt); border-block: 1px solid var(--line);
        padding: 3rem 0; margin: 3rem 0; }

/* Sits at the top of <main>; the hero below carries a matching, smaller top
   padding so trail → title reads as one measured step, not a gap. */
.breadcrumbs { font-size: .8rem; color: var(--muted); padding: 1.125rem 0 0;
               line-height: 1.5; }
.breadcrumbs a { color: var(--accent-deep); }
.breadcrumbs ol { list-style: none; display: flex; flex-wrap: wrap; gap: .4rem;
                  margin: 0; padding: 0; }
.breadcrumbs li::after { content: "›"; margin-left: .4rem; color: var(--sand); }
.breadcrumbs li:last-child::after { content: ""; }

.prose { font-size: 1.0625rem; line-height: 1.7; }
.prose h2 { margin-top: 2rem; }
.prose h3 { margin-top: 1.5rem; }
.prose ul, .prose ol { padding-left: 1.25rem; }
.prose blockquote {
  margin: 1.5rem 0; padding: .25rem 0 .25rem 1.25rem;
  border-left: 3px solid var(--accent); font-family: var(--font-serif);
  font-style: italic; color: var(--ink-soft);
}
.prose table { width: 100%; border-collapse: collapse; }
.prose td, .prose th { border: 1px solid var(--line); padding: .5rem .75rem;
                       text-align: left; }
.table-scroll { overflow-x: auto; }

.muted { color: var(--muted); }
.faint { color: var(--faint); }
.small { font-size: .8rem; }
.serif { font-family: var(--font-serif); }
.stack > * + * { margin-top: 1rem; }
.cluster { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
.center { text-align: center; }
.home-hero { position: relative; padding-top: 4rem; padding-bottom: 1.5rem; }
.home-hero h1 { margin-bottom: .75rem; }
/* The measure is deliberate — the line reads badly at the h1's full 752px —
   but a max-width without auto side margins leaves the box flush left inside
   a centred container, and `text-align: center` then centres the text on the
   BOX, not on the page: the lead sat on x=584 while the heading and the search
   field sat on x=720. It only looked intermittent because a short string (or a
   fallback font wrapping it to two lines) can sit mid-box and pass for
   centred, while the longer Uzbek string fills the box and exposes the offset. */
.home-hero__lead { max-width: 30rem; margin-inline: auto; margin-bottom: 1.75rem; }
@media (max-width: 640px) {
  .home-hero { padding-top: 2rem; }
  .home-hero__lead { margin-bottom: 1.5rem; font-size: 1rem; }
}

/* forms */
.field { margin-bottom: 1.125rem; }
.field label { display: block; font-weight: 500; font-size: .9rem;
               margin-bottom: .375rem; }
.field .help { font-size: .8rem; color: var(--muted); margin-top: .25rem; }
.field .errorlist { list-style: none; margin: .375rem 0 0; padding: 0;
                    color: var(--err); font-size: .85rem; }
input[type="text"], input[type="email"], input[type="search"], input[type="url"],
select, textarea {
  width: 100%; font: inherit; color: var(--ink); background: var(--white);
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  padding: .625rem .75rem; min-height: 44px;
}
textarea { min-height: 8rem; resize: vertical; }
.checkbox { display: flex; gap: .625rem; align-items: flex-start; }
.checkbox input { width: 20px; height: 20px; min-height: 0; margin-top: .15rem; }
.checkbox label { font-weight: 400; }

.alert { border-radius: var(--radius); padding: .875rem 1.125rem;
         margin-bottom: 1.25rem; border: 1px solid var(--line-strong);
         background: var(--white); }
.alert--success { background: var(--ok-wash); border-color: var(--ok-line); color: var(--ok-ink); }
.alert--error { background: var(--err-wash); border-color: var(--err-line); color: var(--err-ink); }
.alert--info { background: var(--paper-alt); }

/* a standing note that a section is not finished (see TZ scope notes) */
.stub-note {
  display: flex; gap: .875rem; align-items: flex-start;
  background: var(--paper-alt); border: 1px dashed var(--sand);
  border-radius: var(--radius); padding: 1rem 1.125rem;
  /* Equal above and below. With a bottom margin only, the note inherited
     whatever the paragraph above it happened to leave — 16px, the tightest
     gap on the page and barely half the 28px beneath it, so a bordered box
     sat clamped against the running text it is meant to stand apart from.
     The top margin collapses with the paragraph's, so this sets the gap
     rather than adding to it. */
  margin-block: 1.75rem;
  font-size: .9rem; color: var(--ink-soft);
}
.stub-note strong { color: var(--ink); }

.pagination { display: flex; gap: .5rem; justify-content: center;
              align-items: center; margin: 2rem 0; flex-wrap: wrap; }
.pagination a, .pagination span {
  min-width: 44px; min-height: 44px; padding: .5rem .75rem;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--white); color: var(--ink);
}
.pagination .current { background: var(--ink); color: var(--paper);
                       border-color: var(--ink); }

.empty { text-align: center; padding: 3rem 1rem; color: var(--muted); }

/* Catalogue filter: the <summary> is the whole results toolbar — count on the
   left, a small "filter" button on the right — so folded it costs one line
   and there is no card around a card. The panel unfolds beneath. */
.tales-catalog .filters { margin: 0 0 1.25rem; }
.filters__summary {
  cursor: pointer; list-style: none;
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; min-height: 44px;
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
  padding: .25rem 0;
}
.filters__summary::-webkit-details-marker { display: none; }
.filters__summary::marker { content: ""; }
.filters__btn {
  display: inline-flex; align-items: center; gap: .45rem;
  font-size: .875rem; font-weight: 500; color: var(--ink);
  padding: .3rem .75rem; border: 1px solid var(--line-strong);
  border-radius: 99px; background: var(--white); white-space: nowrap;
  transition: border-color .15s ease, background .15s ease;
}
.filters__summary:hover .filters__btn { border-color: var(--sand); }
.filters__chev {
  width: .5rem; height: .5rem; border-right: 1.6px solid currentColor;
  border-bottom: 1.6px solid currentColor; transform: rotate(45deg);
  margin: -.2rem 0 0 .1rem; transition: transform .2s ease;
}
.filters__details[open] .filters__btn { background: var(--paper-alt); border-color: var(--sand); }
.filters__details[open] .filters__chev { transform: rotate(-135deg); margin-top: .2rem; }
.filters__panel { margin-top: .875rem; }
.filters__active { margin: -.5rem 0 1rem; }
.filters__checks { display: flex; flex-wrap: wrap; gap: 1rem; margin-top: 1rem; }
.filters__actions { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: 1rem; }
/* The trailing air before the footer; the grid itself ends flush. */
.tales-catalog { padding-bottom: 3rem; }

/* dialect map */
.dialect-map__scroll { overflow-x: auto; }

/* -------------------------------------------------------------------- footer */
.footer { margin-top: auto; background: var(--band); color: var(--band-ink);
          padding: 2.75rem 0 0; }
.footer a { color: var(--band-ink); }
.footer__grid { display: grid; grid-template-columns: 1.3fr 1fr 1fr 1.3fr;
                gap: 1.875rem; padding-bottom: 1.875rem; }
.footer__title { font-size: .7rem; letter-spacing: .14em; text-transform: uppercase;
                 color: var(--band-faint); font-weight: 700; display: block;
                 margin-bottom: .75rem; }
.footer__list { display: flex; flex-direction: column; gap: .5rem;
                font-size: .875rem; }
.footer__brand { display: flex; align-items: center; gap: .7rem; }
.footer__brand img { width: 26px; height: 24px; }
.footer__logo { height: 60px; width: auto; max-width: 100%; display: block; }
/* Footer partners: a role, then the mark — one pair per row, all marks
   left-aligned at one optical weight on the dark band. */
.partners { margin: 0; display: flex; flex-direction: column; gap: 1.25rem; }
.partners__row { display: flex; flex-direction: column; gap: .5rem; }
.partners dt { font-size: .75rem; color: var(--band-faint); }
.partners dd { margin: 0; }
.partners__marks { display: flex; align-items: center; flex-wrap: wrap;
                   gap: .75rem 1.5rem; }
.partners__logo { display: block; height: auto; max-width: 100%; }
.partners__logo--gross { width: 94px; }
.partners__logo--nma { width: 116px; }
.partners__logo--centrum { width: 190px; }
.partners__logo--hayot { width: 120px; }
.footer__bottom { border-top: 1px solid rgba(255,255,255,.12); }
.footer__bottom .wrap { display: flex; justify-content: space-between;
                        gap: 1rem; flex-wrap: wrap; padding-block: 1rem;
                        font-size: .75rem; color: var(--band-faint); }

/* ------------------------------------------------------------------ responsive */
@media (max-width: 900px) {
  .grid--4, .grid--cards { grid-template-columns: repeat(2, 1fr); }
  .grid--sidebar { grid-template-columns: 1fr; }
  .footer__grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .grid--2, .grid--3, .grid--4 { grid-template-columns: 1fr; }
  .grid--cards { grid-template-columns: repeat(2, 1fr); gap: .875rem; }
  .footer__grid { grid-template-columns: 1fr; }
  .section-head { flex-direction: column; align-items: flex-start; gap: .25rem; }
  .band { padding: 2rem 0; margin: 2rem 0; }

  /* --- compact header -------------------------------------------------
     On a phone the header was costing ~650px before any content. What
     survives is what a reader actually needs here: identity, the script
     switch (TZ 4.1.2 requires it to stay permanently reachable), search,
     and the four sections. The strapline and the secondary links are cut —
     both are reachable in the footer. */
  /* Nothing in the top strip survives on a phone: the strapline and the
     secondary links both live in the footer, and the switch has moved into
     the brand row. */
  .topbar { display: none; }
  .lang-menu--wide { display: none; }
  .lang-menu--narrow { display: block; margin-left: auto; margin-right: .5rem; }
  .lang-menu > summary { min-height: 36px; }

  /* No bottom padding here: the nav row is the last child and owns its own
     symmetric padding, otherwise this padding lands under the links only
     and the row reads as sitting too high in its band. */
  .masthead__inner { padding: .625rem 0 0; gap: .625rem; flex-wrap: wrap; }
  /* The lockup is a block two lines deep, and at this width that pushed the
     search button onto a row of its own. Below 640 the descriptor goes — the
     brand book drops it under 128px too — and the mark alone keeps the
     masthead one line. */
  /* The full lockup on phones too, descriptor included (the owner's call):
     it takes the room the menu and search leave, up to 48px tall, so the
     wider Russian lockup still fits a 320px screen. */
  .brand { flex: 1 1 0; min-width: 0; }
  .brand__logo { width: auto; height: auto; max-width: 100%; max-height: 48px; }
  .icon-btn { width: 40px; height: 40px; flex: none; }

  .nav {
    order: 3; width: 100%; margin-left: 0; gap: 1.25rem;
    flex-wrap: nowrap; overflow-x: auto; overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    border-top: 1px solid var(--line);
    padding-block: .25rem;
  }
  .nav::-webkit-scrollbar { display: none; }
  /* The nav row scrolls sideways and would clip the panel; with the details
     unpositioned, the panel's containing block is the header row instead. */
  .masthead__inner { position: relative; }
  .nav-menu { position: static; }
  .nav-menu > summary { min-height: 40px; font-size: .9375rem; }
  .nav-menu__list { left: 0; right: auto; top: 100%; }
  .nav a { min-height: 40px; white-space: nowrap; font-size: .9375rem; }

  /* The filter panel was pushing the results a full screen down; on a phone it
     starts collapsed (ui.js) unless a filter is already applied. */
  .filters__checks { gap: .625rem; flex-direction: column; }
  .filters__actions .btn { flex: 1 1 auto; }

  /* TZ 4.2.3а: on small screens the region list is the navigation, so it comes
     first; the schematic map follows and scrolls sideways rather than shrinking
     its labels into illegibility. */
  .dialect-side { order: -1; }
  .dialect-map__scroll svg { min-width: 30rem; }
  .dialect-map text { font-size: 13px; }
  .dialect-side .footer__list { display: grid;
    grid-template-columns: repeat(2, 1fr); gap: .5rem .75rem; }
}

/* Very small screens still have to work — TZ 4.1.6 sets the floor at 320px. */
@media (max-width: 380px) {
  .wrap { padding: 0 1rem; }

  .icon-btn { width: 36px; height: 36px; }
  .nav { gap: 1rem; }
  .nav a { font-size: .875rem; }
}

/* ===========================================================================
   Motion
   The portal is server-rendered, so navigation is a real document load, and
   it is shown as one: the old page stays up until the new page has fully
   arrived (see `rel="expect"` in base.html), then the browser swaps them in
   a single frame. There is deliberately no cross-document view transition.
   One was tried — a quarter-second cross-fade with the masthead held still —
   and in about half of navigations Chromium lost the snapshot of the old
   page, so the reader saw the page go blank under the header and the new one
   fade up out of nothing. A cut between two finished pages is not a glitch;
   a fade that sometimes starts from blank is.
   ======================================================================== */
@media (prefers-reduced-motion: no-preference) {
  /* Home hero: a short stagger on first paint. */
  .home-hero > h1, .home-hero > p, .home-hero > form, .home-hero > .rule {
    animation: hero-rise .45s cubic-bezier(.2, .7, .3, 1) both;
  }
  .home-hero > p { animation-delay: .05s; }
  .home-hero > form { animation-delay: .1s; }
  .home-hero > .rule { animation-delay: .15s; }
}

/* Opacity only, deliberately. This used to lift the hero a few pixels as it
   faded in, and the effect was a gap opening under the header on arrival and
   closing again over the next fifth of a second. Read as a margin appearing
   and then disappearing — a layout fault rather than a transition. A page
   that has only just loaded should not still be moving. */
@keyframes hero-rise { from { opacity: 0; } }

/* Indeterminate navigation bar — see js/progress.js. It is only revealed when
   a navigation actually takes long enough to be worth reporting. */
.navbar-progress {
  position: fixed; inset: 0 auto auto 0; height: 3px; width: 0;
  background: var(--accent); z-index: 200; opacity: 0;
  transition: width .2s ease, opacity .2s ease;
  pointer-events: none;
}
.navbar-progress.is-active { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important; transition-duration: .001ms !important;
  }
  .navbar-progress { transition: none; }
}

@media print {
  .topbar, .nav, .footer, .lang-menu, .searchbox { display: none; }
  body { background: #fff; }
}

/* --- a structured dictionary article ---------------------------------------
   The shape a printed dictionary uses: senses numbered under the part of
   speech they belong to, labels set apart from the text they qualify,
   examples and collocations distinguishable at a glance. */
.article__head { margin: 0 0 .5rem; display: flex; gap: .5rem; align-items: baseline; flex-wrap: wrap; }
.article__homograph { font-weight: 700; color: var(--accent-deep); }
.article__ipa { font-size: .9375rem; color: var(--muted); }
.article__etymology { margin: 0 0 .625rem; font-size: .875rem; color: var(--muted); }

.article__label {
  font-style: italic; font-size: .8125rem; color: var(--accent-deep);
  margin-right: .375rem;
}
.block + .block { margin-top: .875rem; padding-top: .75rem; border-top: 1px solid var(--line); }
.block__n { font-weight: 700; color: var(--ink); margin-right: .25rem; }
.block__pos { font-style: italic; font-weight: 600; color: var(--ink-soft); margin-right: .375rem; }
.block__grammar { font-size: .875rem; color: var(--muted); margin-right: .375rem; }

.sense { margin: .375rem 0 0; }
.sense__n { font-weight: 600; color: var(--faint); margin-right: .25rem; }
.sense__def { color: var(--ink); }
.sense__equivalents { color: var(--ink); }
.sense__equivalents .sep { color: var(--faint); }
/* A sense answered in several languages: one row per language, the name of
   the language set small against the left so the eye can skip to the one it
   reads. */
.equivalents { display: block; margin-top: .375rem; }
.equivalents__row {
  display: flex; gap: .625rem; align-items: baseline;
  margin-top: .1875rem;
}
.equivalents__lang {
  flex: 0 0 5.25rem; font-size: .72rem; letter-spacing: .08em;
  text-transform: uppercase; color: var(--faint); text-align: right;
}
.equivalents__list { flex: 1 1 auto; min-width: 0; color: var(--ink); }
/* dir="rtl" is what puts an Arabic phrase's punctuation at the right end of
   it, but it also right-aligns the whole line, which leaves the row floating
   away from the language that names it. The direction is kept; the alignment
   is not. */
.equivalents__list[dir="rtl"] { text-align: left; }
.equivalents__list .sep { color: var(--faint); }
@media (max-width: 30rem) {
  /* Stacked, the language name reads as a heading and its translations as
     what sits under it, so they are indented clear of it. */
  .equivalents__row { display: block; margin-top: .375rem; }
  .equivalents__lang { display: block; text-align: left; margin-bottom: .125rem; }
  .equivalents__list { display: block; padding-left: .875rem; }
}

/* The translation of a sense that also carries an explanation. It is the
   answer an Uzbek reader came for, and the explanation above it is in the
   source's own language and often its own alphabet, so the two are set apart
   rather than joined by a semicolon. */
.sense__equivalents--own {
  display: block; margin-top: .375rem; padding-left: .75rem;
  border-left: 2px solid var(--sand); font-weight: 600;
}

/* Collocations hang under the sense they belong to, indented so the eye can
   tell an illustration from the definition above it. */
.collocations { list-style: none; margin: .375rem 0 0; padding: 0 0 0 1.25rem; }
.collocations li {
  margin: .3125rem 0; font-size: .9375rem; text-indent: -1.25rem;
  padding-left: 1.25rem; line-height: 1.5;
}
.collocations li::before { content: "◆"; color: var(--sand); margin-right: .5rem; font-size: .75rem; }
.colloc__phrase { font-weight: 600; color: var(--ink); }
/* The phrase and what it means are two languages saying one thing. Set on the
   same line they read as a single broken sentence — «преодолеть все
   препятствия barcha toʻsqinliklarni yengmoq». A phone stacked them because it
   had no room; a desktop has the room and ran them together. text-indent is
   inherited, so the hanging indent of the bullet must be cancelled here or the
   gloss starts 1.25rem to the left of the phrase above it. */
.colloc__gloss { display: block; color: var(--muted); text-indent: 0; }
.collocations--entry { margin-top: .875rem; padding-top: .625rem; border-top: 1px solid var(--line); }
/* Nothing to separate the phrases from when they are the whole article. */
.article > .collocations--entry:first-child {
  margin-top: 0; padding-top: 0; border-top: 0;
}
/* A phrase's own citation, set under it rather than beside it. */
.example--phrase { display: block; margin-top: .1875rem; text-indent: 0; }

.example {
  margin: .375rem 0 0; font-family: var(--font-serif); font-style: italic;
  color: var(--ink-soft); font-size: .9375rem;
}
/* Likewise the citation and its translation. */
.example__tr { display: block; font-style: normal; color: var(--muted); text-indent: 0; }
/* A parenthetical qualifies rather than continues — «voz kechmoq (taxtdan)». */
.qualifier { font-style: italic; color: var(--muted); }
.example__src { font-style: normal; font-size: .8125rem; color: var(--faint); }

.article__relations { margin: .875rem 0 0; font-size: .875rem; color: var(--ink-soft); }
.article__rel-label { font-size: .72rem; letter-spacing: .1em; text-transform: uppercase;
                      color: var(--faint); margin-right: .375rem; }

/* The home page's opening band: the word of the day, and the statistics and
   dialect-appeal cards beside it. `align-items: start` let each column take
   its own height, so the row ended twice — the left card 86px short of the
   right column — and the ragged seam showed against the section below.

   Stretching alone would only move the gap inside the taller column, so both
   sides fill it: the word card becomes a flex column with its link pushed to
   the foot, and the pair beside it spreads to meet it. Whichever side is
   taller, the two bottoms meet. */
.hero-row { align-items: stretch; position: relative; z-index: 1; }
.hero-row > .card { display: flex; flex-direction: column; }
.hero-row > .stack { justify-content: space-between; }
.hero-row__cta { margin: 1rem 0 0; }
/* Kun soʻzi: the word is a heading, not a signboard — one step above the
   card's own h2, sentence case, and the source under it in the smallest
   setting so the gloss is what the eye lands on. */
.wotd__head { display: flex; flex-wrap: wrap; align-items: center;
              gap: .375rem .75rem; margin-top: .625rem; }
.wotd__word { font-family: var(--font-serif); font-size: 1.625rem; font-weight: 600;
              line-height: 1.2; letter-spacing: -.01em; overflow-wrap: anywhere; }
.wotd__source { margin: .25rem 0 0; }
.wotd__gloss { margin: .75rem 0 0; max-width: 40ch; }
.wotd__senses { margin: .75rem 0 0; padding-left: 1.25rem; max-width: 40ch; }
.wotd__senses li { margin: 0 0 .375rem; }
.wotd__senses li::marker { color: var(--faint); font-size: .875rem; }
.wotd__example { margin: .5rem 0 0; font-style: italic; color: var(--ink-soft);
                 max-width: 40ch; }
@media (min-width: 56.25rem) {
  /* Only once there is a column beside it to line up with. Stacked, this
     would strand the link at the bottom of a tall card. */
  .hero-row__cta { margin-top: auto; padding-top: 1rem; }
}

/* The word page's second column. It follows a page that can run very long —
   fourteen dictionaries deep — so it travels with the reader rather than
   scrolling away at the first card. Sticky only where there is a viewport
   tall enough to spare; below that it is an ordinary block that stacks under
   the article via .grid--sidebar's own breakpoint. */
.word-aside { position: sticky; top: 1.5rem; }
@media (max-width: 900px), (max-height: 34rem) {
  .word-aside { position: static; }
}
.word-aside__list {
  margin: .625rem 0 0; padding-left: 1.25rem;
  font-size: .875rem; line-height: 1.5;
}
.word-aside__list li { margin-bottom: .375rem; }

/* --- a structured article previewed in a search result ---------------------
   Clipped rather than summarised: the reader sees the real shape of the entry
   and can tell whether it answers them before following the link. */
.preview { position: relative; margin-top: .5rem; }
/* Room for a short article whole — two or three senses with an example — so
   the clip is met only by the long ones. */
.preview > .article { max-height: 16rem; overflow: hidden; }
/* The fade is drawn only where something was actually cut off (ui.js marks
   it): laid over a one-line article it washed the article out for nothing. */
.preview.is-clipped > .article::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 1.5rem; height: 3rem;
  background: linear-gradient(to bottom, transparent, var(--white));
  pointer-events: none;
}
.preview__more {
  display: inline-block; margin-top: .25rem; font-size: .8125rem;
  color: var(--accent-deep);
}
/* Kept even where the whole article fits: the link does not open that article
   — it opens the card, and «til» is one short Turkish entry here and ten more
   dictionaries behind it. Hiding it made two cards in the same list, one with
   a way in and one without, look like two different kinds of result. */
.preview .article__pos-n, .preview .block__n { color: var(--ink-soft); }

/* The head of one dictionary's article — «BAY I», «CUT [kʌt]». A rule
   separates a second article of the same book from the first. */
.entry-head {
  margin: 1.375rem 0 .375rem; display: flex; gap: .4375rem; align-items: baseline;
  flex-wrap: wrap; padding-top: 1rem; border-top: 1px solid var(--line);
}
.entry-head:first-of-type { border-top: 0; padding-top: 0; margin-top: .5rem; }
/* Small enough not to compete with the page's own headword above it. */
.entry-head__word {
  font-family: var(--font-serif); font-size: 1.0625rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: .01em; color: var(--ink);
}
.entry-head__n {
  font-family: var(--font-serif); font-weight: 700; font-size: 1.0625rem;
  color: var(--accent-deep);
}


/* Search results: the count, with what is narrowing it, and the filters —
   folded away until wanted, because most searches are just a word and the
   controls would otherwise sit between the reader and the answer. Closed it
   is one short line; open it is only the rows there is a choice in. */
.results-count {
  display: flex; flex-wrap: wrap; align-items: center; gap: .375rem .5rem;
  margin: 0; color: var(--muted);
}
.chip {
  display: inline-flex; align-items: center; gap: .3rem;
  padding: .0625rem .5rem .0625rem .625rem; border-radius: 99px;
  background: var(--ink); color: var(--paper); font-size: .75rem;
  line-height: 1.6; min-height: 26px; text-decoration: none;
}
.chip span { font-size: .95rem; line-height: 1; opacity: .7; }
.chip:hover { text-decoration: none; background: var(--ink-soft); }
.chip:hover span { opacity: 1; }
.chip--quiet { background: transparent; color: var(--accent-deep); padding-inline: .25rem; }
.chip--quiet:hover { background: transparent; text-decoration: underline; }

.filters { margin: .5rem 0 1.5rem; }
.filters__toggle {
  cursor: pointer; font-size: .875rem; color: var(--ink-soft);
  padding: .25rem 0; list-style: none; display: inline-flex; gap: .375rem;
  align-items: center; min-height: 32px;
}
.filters__toggle::-webkit-details-marker { display: none; }
.filters__toggle::before { content: "\2261"; color: var(--faint); }
.filters[open] .filters__toggle { margin-bottom: .25rem; }
.filters__row {
  display: flex; gap: .625rem; align-items: baseline; margin-top: .375rem;
  flex-wrap: wrap;
}
.filters__label {
  flex: 0 0 5.5rem; font-size: .72rem; letter-spacing: .08em;
  text-transform: uppercase; color: var(--faint); text-align: right;
}
.cluster--tight { gap: .375rem; }
.pill--sm { font-size: .8125rem; padding: .125rem .625rem; min-height: 28px; }
.pill--sm.pill--active { gap: .3rem; padding-right: .5rem; }
.pill--sm.pill--active span { opacity: .7; line-height: 1; }
@media (max-width: 34rem) {
  .filters__row { display: block; }
  .filters__label { display: block; text-align: left; margin-bottom: .25rem; }
}

/* ===========================================================================
   Tale cards (tales/_card.html) — catalogue, compiler page, home.
   The cover is a 3:4 plate. Until it arrives the frame is painted in the
   cover's own dominant colour (Tale.cover_color), so a page of cards fills
   in as a set of tinted plates that resolve into pictures, not a grid of
   white holes that pop one by one.
   ======================================================================== */
.tale-card { display: flex; flex-direction: column; gap: .625rem; min-width: 0; }
.tale-card__cover {
  --cover-color: var(--paper-warm);
  display: block; position: relative; aspect-ratio: 3 / 4; overflow: hidden;
  border-radius: var(--radius-sm); background: var(--cover-color);
  box-shadow: var(--shadow-sm), var(--hairline-inset);
  transition: transform .35s cubic-bezier(.2,.8,.2,1), box-shadow .35s ease;
}
.tale-card__cover img {
  display: block; width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transition: opacity .5s ease;
}
.tale-card__cover img.is-loaded { opacity: 1; }
.tale-card__blank { position: absolute; inset: 0; display: flex; align-items: center;
                    justify-content: center; }
.tale-card__blank i { width: 12px; height: 12px; border: 1.5px solid var(--sand);
                      transform: rotate(45deg); }
.tale-card:hover .tale-card__cover, .tale-card:focus-within .tale-card__cover {
  transform: translateY(-3px); box-shadow: var(--shadow), var(--hairline-inset);
}
.tale-card__title {
  font-family: var(--font-serif); font-size: 1.05rem; font-weight: 600; line-height: 1.3;
  color: var(--ink); text-wrap: balance;
}
.tale-card__title:hover { color: var(--accent-deep); text-decoration: none; }
.tale-card__meta { display: flex; flex-wrap: wrap; gap: .375rem; margin-top: auto; }
.tale-card__meta .badge { display: inline-flex; align-items: center; gap: .3rem; }
@media (prefers-reduced-motion: reduce) {
  .tale-card__cover, .tale-card__cover img { transition: none; }
}

/* catalogue: hero row with search, result count and the compact filter bar */
.tales-hero { display: grid; grid-template-columns: 1.4fr 1fr; gap: 2rem; align-items: end;
              padding-block: 2.5rem 1.5rem; }
.tales-hero p { margin: 0; }
.tales-search { display: flex; gap: .5rem; }
.tales-search input {
  flex: 1; min-height: 46px; padding: .5rem 1rem; border-radius: 9px;
  border: 1px solid var(--line-strong); background: var(--white); font: inherit; color: var(--ink);
}
.tales-search input:focus { outline: 2px solid var(--accent); outline-offset: 1px; border-color: transparent; }
.tales-count { font-size: .875rem; color: var(--muted); }
.tales-count strong { color: var(--ink); }
@media (max-width: 760px) {
  .tales-hero { grid-template-columns: 1fr; gap: 1.25rem; padding-block: 1.5rem 1.25rem; }
  .tales-hero p { font-size: .9375rem; }
  .tales-search .btn { padding-inline: 1rem; }
  .filters__checks { margin-top: 1.25rem; }
  .filters__panel .grid--3 { gap: .875rem; }
}

/* tale page */
.tale-hero { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 3rem;
             align-items: start; padding-block: 1.5rem 3rem; }
.tale-hero h1 { margin-top: .25rem; }
.tale-hero__cover { position: sticky; top: 1.5rem; }
.tale-hero__cover img, .tale-hero__cover .tale-card__cover {
  display: block; width: 100%; aspect-ratio: 3 / 4; object-fit: cover;
  border-radius: var(--radius); box-shadow: var(--shadow-lg);
}
.tale-hero__facts { display: flex; flex-wrap: wrap; gap: .75rem 1.25rem; font-size: .875rem;
                    color: var(--muted); margin: 1rem 0 1.25rem; }
.tale-hero__facts span { display: inline-flex; align-items: center; gap: .4rem; }
.tale-hero__facts svg { color: var(--accent-deep); flex: none; }
.tale-hero__cta { display: flex; flex-wrap: wrap; gap: .625rem; margin-top: 1.75rem; }
.tale-hero__cta .btn { min-width: 9rem; }
.tale-hero__chars { margin-top: 1.5rem; }
.tale-hero__source { font-size: .8125rem; color: var(--faint); margin-top: 1.75rem; padding-top: 1rem;
                     border-top: 1px solid var(--line); }
.tale-hero__source .badge { vertical-align: middle; margin-left: .375rem; }
@media (max-width: 900px) {
  /* One column: the cover becomes a centred frontispiece and the title block
     under it is centred too, so the page opens like a book rather than with
     a thumbnail parked in the top-left corner. Body copy stays left-aligned. */
  .tale-hero { grid-template-columns: 1fr; gap: 1.5rem; padding-block: 1.25rem 2.5rem; }
  .tale-hero__cover { position: static; order: -1; width: min(56%, 220px);
                      margin: .25rem auto 0; }
  .tale-hero > div > .eyebrow:first-child { display: block; text-align: center; }
  .tale-hero h1 { text-align: center; }
  .tale-hero__facts { justify-content: center; }
  .tale-hero__cta { justify-content: center; }
  .tale-hero__cta .btn { flex: 1 1 auto; }
}

/* Word page: the languages a spelling is a word in. One row that scrolls on
   a phone — wrapped, four languages stood four lines above the heading. */
.lang-tabs {
  display: flex; flex-wrap: wrap; align-items: center; gap: .375rem;
  margin-bottom: .875rem;
}
.lang-tabs__n { opacity: .6; font-variant-numeric: tabular-nums; }
.lang-tabs .pill { white-space: nowrap; }
@media (max-width: 640px) {
  .lang-tabs {
    flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none;
    margin-inline: -1.5rem; padding-inline: 1.5rem;
  }
  .lang-tabs::-webkit-scrollbar { display: none; }
}
@media (max-width: 380px) {
  .lang-tabs { margin-inline: -1rem; padding-inline: 1rem; }
}

/* A video in a CMS page (the About page's film): the text column's width,
   16:9, and nothing of YouTube's chrome around it until it is played. */
.prose .video { margin: 0 0 1.75rem; aspect-ratio: 16 / 9; width: 100%;
                border-radius: var(--radius); overflow: hidden; background: #000; }
.prose .video iframe { width: 100%; height: 100%; border: 0; display: block; }

/* ---- Resources catalogue -------------------------------------------------
   The index is the catalogue: a jump row of rubrics, then each rubric's links
   as tiles. A tile is one link — mark, name, domain, what it is for — so the
   whole card is the target, and where it leads is said before it is followed. */
.res-search { display: flex; gap: .5rem; max-width: 40rem; margin-top: 1.5rem; }
.res-search input {
  flex: 1; min-width: 0; font: inherit; padding: .7rem 1rem;
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  background: var(--white); color: var(--ink);
}
.res-search input:focus { outline: 2px solid var(--accent); outline-offset: 1px; border-color: transparent; }
.res-jump { display: flex; flex-wrap: wrap; gap: .5rem; margin: 1.75rem 0 .5rem; }
.res-jump .pill .faint { font-variant-numeric: tabular-nums; }
.res-section { margin-top: 2.75rem; scroll-margin-top: 1.5rem; }
.res-section .section-head { align-items: baseline; }
.res-section__lead { margin: -.25rem 0 1rem; max-width: 44rem; }
.res-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1rem; }
@media (max-width: 1000px) { .res-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 640px)  { .res-grid { grid-template-columns: 1fr; } .res-search { flex-direction: column; } }

.res-tile {
  display: flex; flex-direction: column; gap: .625rem;
  padding: 1.125rem 1.25rem; border-radius: var(--radius);
  background: var(--white); border: 1px solid var(--line);
  color: var(--ink); text-decoration: none;
  transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}
.res-tile:hover { text-decoration: none; border-color: var(--sand);
                  box-shadow: var(--shadow-sm); transform: translateY(-1px); }
.res-tile:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.res-tile__head { display: flex; gap: .75rem; align-items: center; }
.res-tile__mark {
  flex: none; width: 40px; height: 40px; border-radius: 10px;
  display: grid; place-items: center; font-weight: 700; font-size: 1.05rem;
  background: var(--accent-wash); color: var(--accent-deep);
}
.res-tile__titles { display: flex; flex-direction: column; min-width: 0; }
.res-tile__name { font-weight: 600; line-height: 1.3; }
.res-tile__domain { font-size: .8rem; color: var(--faint); }
.res-tile:hover .res-tile__domain { color: var(--accent-deep); }
.res-tile__desc { font-size: .875rem; color: var(--muted); line-height: 1.5; }
.res-tile__meta { display: flex; flex-wrap: wrap; gap: .375rem .625rem; align-items: center;
                  margin-top: auto; font-size: .75rem; color: var(--faint); }
.res-suggest { display: flex; justify-content: space-between; align-items: center;
               gap: 1rem; flex-wrap: wrap; margin-top: 3rem; }
/* A site's own icon sits on a white plate in both themes, as an app icon
   does — dark marks such as Wikipedia's «W» would vanish on the dark ground. */
.res-tile__mark--icon { background: #fff; border: 1px solid var(--line); }
.res-tile__mark--icon img { width: 24px; height: 24px; object-fit: contain; }
/* A recommended resource: first in its rubric, a gold edge and wash, and a
   «Tavsiya etamiz» flag — set per resource in the CMS. Gold, not the coral,
   so a recommendation does not read as a link or an alert. */
.res-tile--featured {
  border-color: color-mix(in srgb, var(--gold) 55%, var(--line));
  background: linear-gradient(180deg, var(--gold-wash), var(--white) 75%);
  box-shadow: inset 3px 0 0 var(--gold);
}
.res-tile--featured:hover { border-color: var(--gold); }
.res-tile__head { position: relative; }
.res-tile__flag {
  margin-left: auto; align-self: flex-start; flex: none;
  font-size: .68rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--gold-ink); background: var(--gold);
  padding: .2rem .55rem; border-radius: 99px;
}
/* The About film exists in both Uzbek scripts; the page shows the one in the
   script the reader chose. The hidden one is lazy and so never loads. */
[data-script="cyrl"] .prose .video--latn,
[data-script="latn"] .prose .video--cyrl { display: none; }
