/* Platforma Sans — BCDH's Open Sans derivative, drawn for the Raskovnik
   dictionary so that Serbian combining accents (U+030F, U+0300, U+0311,
   U+0301, U+0304) sit correctly over Cyrillic rather than colliding with the
   ascender. Apache 2.0; see fonts/LICENSE and fonts/NOTICE.

   It is for dictionary text only — headwords, definitions, synonyms, guide
   words. Buttons, navigation and chrome keep the system stack. */
@font-face {
    font-family: 'Platforma Sans';
    src: url('/fonts/PlatformaSans-Regular.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Platforma Sans';
    src: url('/fonts/PlatformaSans-Italic.woff2') format('woff2');
    font-weight: 400;
    font-style: italic;
    font-display: swap;
}

@font-face {
    font-family: 'Platforma Sans';
    src: url('/fonts/PlatformaSans-Bold.woff2') format('woff2');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}

/* The dictionary's own voice. Falls back to whatever Bootstrap would have
   used, so nothing shifts if the font fails to load. */
.dict {
    font-family: 'Platforma Sans', var(--bs-body-font-family);
}

/* Layout */
body { display: flex; flex-direction: column; min-height: 100vh; }
main { flex: 1; }

/* The site's mark, on a white tile.

   The artwork is #1B64AA blue with a #D31920 red form inside it, and the
   header field is #0C4076 — set straight onto it the blue half of the mark
   disappears and what is left reads as a broken shape. The tile gives it the
   white it was drawn for. Tile and padding come to the 48px the old logo
   stood at, so the header keeps its height. */
/* The two bands are built to the same height: the same vertical padding, and
   in each the tallest thing is 38px — the search field in one, the logo tile
   in the other. The tile is 28px of mark in 5px of white on every side. */
.brand-band .container {
    padding-top: var(--sr-band-padding);
    padding-bottom: var(--sr-band-padding);
}

.site-logo-tile {
    display: inline-flex;
    flex-shrink: 0;
    padding: 5px;
    border-radius: 0.5rem;
    background-color: #fff;
    line-height: 0;
}

.site-logo {
    height: 28px;
    width: auto;
    display: block;
}

/* The software's mark in the footer, held to a line and a half and tinted to
   the colour of the words beside it.

   The file is the white knockout that used to sit on the header, so on a white
   footer there would be nothing to see. It is used as a stencil instead: the
   image decides the shape, `currentColor` fills it, and when the footer's
   colour changes the mark follows without another file being drawn. */
.footer-mark {
    display: inline-block;
    height: 1.5em;
    aspect-ratio: 255 / 144;          /* logo-software.png is 255x144 */
    background-color: currentColor;
    -webkit-mask: url("../img/logo-software.png") center / contain no-repeat;
    mask: url("../img/logo-software.png") center / contain no-repeat;
    opacity: 0.8;
}

.site-brand {
    color: inherit;
    text-decoration: none;
    min-width: 0;
}

.site-brand:hover {
    opacity: 0.85;
}

:root {
    /* The flag: red #C6363C above blue #0C4076 above white. The page is the
       white band, so the header carries the other two — a red rule along the
       top, a blue field, white lettering.

       Blue is the text colour. At 10.44:1 on white it needs no darkening. Red
       is kept for what can be acted on, so a link is still told from the prose
       around it now that the prose is itself blue; 5.26:1 clears AA. */
    --sr-red: #C6363C;
    --sr-red-dark: #A3272D;
    --sr-blue: #0C4076;
    /* The flag blue is much the darker of the two: luminance 0.0505 against
       red's 0.1497. Lightened by a quarter toward white it lands on 0.1497
       exactly, so the band closing the footer carries the same weight as the
       red one opening the header. */
    --sr-blue-band: #486F98;
    --sr-blue-muted: #3a5f8a;
    --sr-rule: #dde5ee;
    --sr-wash: #eef3f9;

    --bs-body-color: #0C4076;
    --bs-primary: #0C4076;
    --bs-primary-rgb: 12, 64, 118;
    --bs-link-color: #C6363C;
    --bs-link-color-rgb: 198, 54, 60;
    --bs-link-hover-color: #A3272D;
}

/* Primary buttons — white text is readable on this dark green */
.btn-primary {
    --bs-btn-bg: #0C4076;
    --bs-btn-border-color: #0C4076;
    --bs-btn-hover-bg: #093157;
    --bs-btn-hover-border-color: #093157;
    --bs-btn-active-bg: #072542;
    --bs-btn-active-border-color: #072542;
    --bs-btn-color: #fff;
    --bs-btn-hover-color: #fff;
    --bs-btn-active-color: #fff;
}

.btn-outline-primary {
    --bs-btn-color: #0C4076;
    --bs-btn-border-color: #0C4076;
    --bs-btn-hover-bg: #0C4076;
    --bs-btn-hover-border-color: #0C4076;
    --bs-btn-hover-color: #fff;
    --bs-btn-active-bg: #093157;
    --bs-btn-active-border-color: #093157;
    --bs-btn-active-color: #fff;
}

/* Header and footer */
/* --- Header weave -------------------------------------------------------
   A cloth-like shimmer over the header field: two sets of soft diagonal
   folds running against each other, which reads as fabric catching light
   rather than as stripes.

   Everything about it is a variable. --sr-weave-light and --sr-weave-dark
   are the highlight and the shadow, so recolouring is two values and the
   pattern stays put; --sr-weave-fold sets how far apart the folds sit and
   --sr-weave-angle how steeply they run. Set both colours to transparent
   to switch it off without removing anything.

   The fold is wide on purpose: at a desktop header width it gives about
   seven folds across. Narrower ones read as stripes rather than cloth.

   The stops are soft rather than hard, so each fold shades in and out like
   a crease instead of ending at an edge. -------------------------------- */
:root {
    /* What makes the red band and the blue one the same height. */
    --sr-band-padding: 0.55rem;

    --sr-weave-light: rgba(255, 255, 255, 0.085);
    --sr-weave-dark: rgba(0, 0, 0, 0.085);
    --sr-weave-fold: 130px;
    --sr-weave-angle: 104deg;
}

/* The flag, read down the page: the brand in red, the search in blue, the
   dictionary itself on white. The red rule that used to open the header is
   gone — the brand band is that red now, and at a band's height rather than
   four pixels. The weave runs over both, which it can because it is two alpha
   overlays and knows nothing about the colour underneath. */
header.brand-band {
    background-color: var(--sr-red);
    background-image:
        repeating-linear-gradient(
            var(--sr-weave-angle),
            transparent 0,
            var(--sr-weave-light) calc(var(--sr-weave-fold) / 2),
            transparent var(--sr-weave-fold)),
        repeating-linear-gradient(
            calc(180deg - var(--sr-weave-angle)),
            transparent 0,
            var(--sr-weave-dark) calc(var(--sr-weave-fold) / 2),
            transparent var(--sr-weave-fold));
}

header .fw-bold,
header .text-muted {
    color: #fff !important;
}

/* Blue, and it stays. The search is in the header so that it is always within
   reach, which only means anything if the band does not scroll away with the
   brand above it.

   Its folds are set closer together than the brand band's: a fold is measured
   across the band, and at the brand's spacing a band this shallow catches one
   of them and reads flat. */
.search-band {
    --sr-weave-fold: 70px;
    position: sticky;
    top: 0;
    z-index: 1030;
    padding: var(--sr-band-padding) 0;
    background-color: var(--sr-blue);
    background-image:
        repeating-linear-gradient(
            var(--sr-weave-angle),
            transparent 0,
            var(--sr-weave-light) calc(var(--sr-weave-fold) / 2),
            transparent var(--sr-weave-fold)),
        repeating-linear-gradient(
            calc(180deg - var(--sr-weave-angle)),
            transparent 0,
            var(--sr-weave-dark) calc(var(--sr-weave-fold) / 2),
            transparent var(--sr-weave-fold));
}

/* The field and the diacritics toggle are one control, and the results hang
   off the bottom of it. */
.search-group {
    position: relative;
}

/* čcć: the three letters the toggle is about, which says it in less room than
   a sentence and in no language in particular. Off, it is a quiet button on
   the end of the field; on, it is filled, because whether it is on changes
   what the search returns and that must be legible at a glance. */
.tolerant-toggle {
    flex: 0 0 auto;
    border: 1px solid var(--bs-border-color);
    border-left: 0;
    background-color: #fff;
    color: var(--sr-blue-muted);
    font-weight: 600;
    letter-spacing: 0.04em;
}

.tolerant-toggle:hover {
    background-color: var(--sr-wash);
    color: var(--sr-blue);
}

.btn-check:checked + .tolerant-toggle {
    background-color: var(--sr-blue);
    border-color: var(--sr-blue);
    color: #fff;
}

.btn-check:focus-visible + .tolerant-toggle {
    box-shadow: 0 0 0 0.25rem rgba(255, 255, 255, 0.5);
}

/* The results, hanging under the field instead of pushing the page down.
   Empty, it is nothing at all: htmx fills it on every keystroke and an empty
   box with a shadow under the field would be a flicker on each one. */
.search-dropdown {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 1040;
    margin-top: 0.3rem;
    max-height: min(60vh, 32rem);
    overflow-y: auto;
    background-color: #fff;
    border-radius: 0.5rem;
    box-shadow: 0 0.5rem 1.5rem rgba(12, 64, 118, 0.25);
}

.search-dropdown:empty,
.search-dropdown.is-hidden {
    display: none;
}

/* The list fills the box: its own rounding and border would show through the
   corners of the one around it. */
.search-dropdown .list-group {
    border-radius: 0.5rem;
}

.search-dropdown .list-group-item:first-child {
    border-top: 0;
}

/* The header inverted: there the red is a band over a blue field, here a blue
   band under a red one, with the red washed out far enough to read small print
   against. */
footer {
    background-color: #fbeeee;
    border-bottom: 4px solid var(--sr-blue-band);
}

/* Search found nothing. Shaped like a result row so it lands in the same
   place on the page, tinted a quiet amber so it registers while typing
   without shouting. */
.search-empty {
    background-color: #fdf8ec;
    border-color: #ead9b0;
    color: #7a5d1e;
}

.search-empty .bi {
    opacity: 0.7;
}

/* "Did you mean" — same amber family as the empty row it follows, a shade
   lighter so the two read as one block rather than two warnings. */
.search-suggest {
    background-color: #fffdf7;
    border: 1px solid #ead9b0;
    border-radius: 0.375rem;
}

.search-suggest a {
    color: #6b4f12;
}

.search-suggest a:hover {
    color: var(--sr-red);
}

/* Home-page showcase boxes. Three words drawn at random, each arguing a
   different case for the dictionary. */
.showcase {
    border-color: var(--sr-rule);
}

.showcase-heading {
    color: var(--sr-blue-muted);
    letter-spacing: 0.04em;
}

.showcase a {
    color: var(--sr-blue);
}

.showcase a:hover {
    color: var(--sr-red);
}

/* Synonym frequency. The shade is the theme green at increasing alpha, not a
   different hue and not the `opacity` property — opacity would fade the word
   itself, and the point is to tint what is behind it. Banding is in
   EntryController.SynonymView.tier(); the counter is derived data, which rule
   3.13 confines to search, so this awaits the author's agreement. */
.freq-1, .freq-2, .freq-3, .freq-4, .freq-5 {
    padding: 0.05em 0.3em;
    border-radius: 0.25rem;
}

.freq-1 { background-color: rgba(12, 64, 118, 0.05); }
.freq-2 { background-color: rgba(12, 64, 118, 0.09); }
.freq-3 { background-color: rgba(12, 64, 118, 0.14); }
.freq-4 { background-color: rgba(12, 64, 118, 0.20); }
.freq-5 { background-color: rgba(12, 64, 118, 0.27); }

/* The word the reader clicked, when it had no entry of its own and the guide
   entry of rule 3.1 is what opened. It takes a red wash in place of whatever
   frequency tint it would have worn — hence the rule sitting after those, since
   both are one class deep and the later one wins. Red over blue was the
   alternative and it reads badly: the flag red falls to 3.2 against the darkest
   tint, under the 4.5 that body text wants. The darker red on this wash is 6.1
   at every tier, and the word loses only its frequency shade, which the ones
   around it still show. */
.origin-word {
    padding: 0.05em 0.3em;
    border-radius: 0.25rem;
    background-color: rgba(198, 54, 60, 0.12);
    color: var(--sr-red-dark);
    font-weight: 600;
}

a.origin-word:hover {
    color: var(--sr-red);
}

/* The figures on the error pages — the scholar for 404, the broken word
   machine for 500. Line art with a transparent background, so each sits on the
   page rather than in a white box, and held back a little so it decorates the
   message instead of competing with it. */
.error-figure {
    width: 220px;
    max-width: 60%;
    height: auto;
    flex-shrink: 0;
    opacity: 0.72;
}

/* Each meaning is two named blocks — Значење and Синоними — rather than one
   run-on line. The headings repeat once per meaning, so they are set small and
   quiet: loud enough to separate the blocks, not loud enough to compete with
   the words themselves. */
.sense-section {
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--sr-blue-muted);
    /* A hairline under the label, in the same pale olive as the showcase
       cards. It separates the blocks without drawing a box around them. */
    border-bottom: 1px solid var(--sr-rule);
    padding-bottom: 0.25rem;
    margin-bottom: 0.5rem;
}

/* A fixed column for the meaning number so the blocks beside it line up. */
.sense-mark {
    flex: 0 0 1.5rem;
}

/* Rule 3.9's neighbouring words. Set quietly beside the entry — they are a
   way out of the page, not part of it. */
.neighbours a {
    color: #5a6b7f;
}

.neighbours a:hover {
    color: var(--sr-red);
}

.neighbours li + li {
    margin-top: 0.15rem;
}

/* The narrow-screen pair, ruled off from the entry above it and split down
   the middle — before on the left, after on the right. */
.neighbours-band {
    border-top: 1px solid var(--sr-rule);
}

.neighbours-split {
    border-right: 1px solid var(--sr-rule);
}

/* The result the arrow keys are sitting on. Tinted rather than outlined, so
   the row does not change size as the selection moves down the list. */
.search-active {
    background-color: var(--sr-wash);
}

.search-active a {
    color: var(--sr-red);
}

/* The way out of the phone takeover is a link, and link red on the band is
   nothing at all. */
.search-band #search-cancel {
    color: #fff;
}

/* A nudge towards the search box for a reader who has arrived and not yet done
   anything: three slow pulses of a soft halo, and then it stops for good.
   Anything the reader does calls it off before or during.

   The halo is white because the field sits in the red band. Blue was the first
   thought and it cannot work here: at a strength you would call discreet it is
   invisible on red, and strong enough to be seen it stops being a hint and
   reads as a focus ring or a validation mark. White at 0.75 is soft against
   red and still unmistakable — light spilling out of the field.

   It stops on its own rather than pulsing away indefinitely — a thing that
   blinks until it is attended to is a thing the reader has to attend to, and
   WCAG asks for anything blinking past five seconds to be stoppable. Three
   pulses take four and a half. Reduced motion gets none of it. */
@keyframes search-invite {
    0%, 100% { box-shadow: 0 0 0 0 rgba(255, 255, 255, 0); }
    50%      { box-shadow: 0 0 0 0.35rem rgba(255, 255, 255, 0.75); }
}

.search-invite {
    animation: search-invite 1.5s ease-in-out 3;
}

@media (prefers-reduced-motion: reduce) {
    .search-invite {
        animation: none;
    }
}

/* The row the search has settled on, and the bar that counts down to opening
   it. The bar sits on the row's bottom edge and is two pixels of the flag red
   — enough to notice out of the corner of an eye, not enough to read as an
   error. It only moves once the script starts it, which it does a second after
   the row settles: the two seconds here and that quiet second make up the
   three before the word opens. */
.search-settled {
    position: relative;
}

.search-countdown {
    position: absolute;
    left: 0;
    bottom: 0;
    height: 2px;
    width: 0;
    background-color: var(--sr-red);
}

.search-countdown.running {
    animation: search-countdown 2s linear forwards;
}

@keyframes search-countdown {
    from { width: 0; }
    to   { width: 100%; }
}

/* Accent editor */
#word-display {
    display: flex;
    flex-wrap: wrap;
    gap: 0.15rem;
    font-size: 2.2rem;
    line-height: 1.6;
}

.letter {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2rem;
    padding: 0.1rem 0.25rem;
    border-radius: 4px;
    font-family: inherit;
    background: none;
    border: 2px solid transparent;
}

.letter-muted {
    color: #6c757d;
    cursor: default;
}

.letter-active {
    cursor: pointer;
    border-color: transparent;
}

.letter-active:hover {
    border-color: transparent;
    background: var(--sr-wash);
}

.letter-selected {
    border-color: transparent !important;
    background: var(--sr-wash);
}

.accent-btn .accent-symbol {
    font-size: 1.2rem;
}

.header-user-icon {
    color: #fff;
    font-size: 1.6rem;
    text-decoration: none;
    opacity: 0.85;
}

.header-user-icon:hover {
    opacity: 1;
    color: #fff;
}
/* ---------------------------------------------------------------------------
   Searching on a phone.

   Measured on a 390x844 screen before any of this: the header took 118px and
   the azbuka strip 141px before the box was reached, and the first result
   began at y=337. A phone keyboard covers 300-340px of the bottom, so the
   reader could see two results. The search has since moved into the header,
   which wins back the strip, but the brand band above it would still cost a
   third of what the keyboard leaves — so while the reader is searching it
   steps aside and the results take the screen.

   The flag survives it: a thin red band at the top where the brand band was,
   then the blue band with the field, then the results on white.

   The class goes on <html>, put there by search.js on focus and only below the
   md breakpoint; nothing here applies to a wider screen.
   --------------------------------------------------------------------------- */

#search-cancel {
    display: none;
}

@media (max-width: 767.98px) {

    .search-takeover body {
        overflow: hidden;
    }

    .search-takeover header,
    .search-takeover footer,
    .search-takeover .alphabet-strip,
    .search-takeover .page-content {
        display: none;
    }

    /* The band becomes the panel. Its height is told to it by search.js from
       window.visualViewport: when the keyboard opens, iOS shrinks that and
       leaves the layout viewport alone, so 100vh — and 100dvh, which follows
       only the browser's own bars — would run on behind the keys and put the
       last results out of reach. The fallback is for the first paint, before
       the script has measured. */
    .search-takeover .search-band {
        position: fixed;
        top: var(--search-top, 0);
        left: 0;
        right: 0;
        z-index: 1050;
        padding-top: 0;
    }

    /* What is left of the red band, so the flag still reads top to bottom. */
    .search-takeover .search-band::before {
        content: "";
        display: block;
        height: 4px;
        margin: 0 -100vmax 0.55rem;     /* across the whole band, not the column */
        background-color: var(--sr-red);
    }

    .search-takeover #search-cancel {
        display: inline-block;
    }

    /* The results stop being a dropdown and become the rest of the screen,
       from the foot of the band down to the keyboard. search.js measures where
       the band ends, because that moves with the keyboard too. */
    .search-takeover .search-dropdown {
        position: fixed;
        top: var(--search-results-top, 4rem);
        left: 0;
        right: 0;
        z-index: 1051;
        /* Not bottom:0 — on iOS the foot of the page is behind the keyboard.
           This is the foot of the visual viewport instead. */
        height: calc(var(--search-top, 0px) + var(--search-height, 100dvh)
                     - var(--search-results-top, 4rem));
        max-height: none;
        margin: 0;
        border-radius: 0;
        box-shadow: none;
        padding-bottom: 1rem;
    }

    .search-takeover .search-dropdown .list-group {
        border-radius: 0;
    }

    /* Condensed rows: 42px each is three results' worth of screen given to
       padding. This is about 34px and still comfortably above the 24px that
       counts as a target you can hit. */
    .search-takeover .search-dropdown .list-group-item {
        padding: 0.3rem 0.6rem;
    }

    .search-takeover .search-dropdown .list-group-item .small {
        font-size: 0.75rem;
    }
}
