/* =============================================================================
   Čaroděj — design system, layer 2: components.

   Every reusable piece of the interface, in one file, grouped by what it is
   rather than by which page first needed it. Page-specific styling does not
   belong here — it goes in `assets/styles/pages/<area>.css` and is imported
   from `assets/app.js`.

   Naming is BEM, taken from the delivered mockup where the mockup had a name
   (`.site-header`, `.main-nav`, `.button`, `.eyebrow`, `.section-label`,
   `.hero*`, `.reading-card*`, `.offering*`, `.site-footer`) and derived in the
   same idiom where it did not. Two vocabularies exist on purpose and are kept
   in step by shared rules rather than by copies:

     `.button` is the canonical name; `.btn` is the same component under the
     name several hundred existing templates and a dozen functional tests use.
     They are declared together, never duplicated.

   Every single-column `display: grid` in this file states
   `grid-template-columns: minmax(0, 1fr)`. A grid with no columns declared gets
   one implicit `auto` track, and an `auto` track's base size is its widest
   child's *min-content* size — which is not clamped to the container. So one
   unbreakable word, one 9-digit figure, one long URL inside a `.page-head` or a
   `.legal` article on a 320 px screen sizes the track past the column and the
   whole page scrolls sideways. `minmax(0, 1fr)` is what `auto` should have
   been: floor of zero, ceiling of the space there actually is.

   /dev/styleguide renders one live example of everything below.
   ============================================================================= */

/* =============================================================================
   Buttons
   ============================================================================= */

.button,
.btn {
    display: inline-flex;
    gap: var(--space-2);
    align-items: center;
    justify-content: center;
    min-height: 42px;
    padding: 0 25px;
    font-size: var(--text-sm);
    font-weight: 650;
    line-height: 1.2;
    color: var(--color-accent-text);
    text-align: center;
    text-decoration: none;
    text-transform: uppercase;
    letter-spacing: 0.18em;
    cursor: pointer;
    background: linear-gradient(180deg, #2a1642, #190e30);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-control);
    box-shadow: inset 0 0 18px rgb(121 52 123 / 13%), 0 0 18px rgb(94 44 105 / 6%);
    transition:
        color var(--transition-fast),
        border-color var(--transition-fast),
        background var(--transition-fast),
        transform var(--transition-fast);
}

.button:hover,
.btn:hover {
    color: var(--color-gold-bright);
    background: linear-gradient(180deg, rgb(79 39 94 / 94%), rgb(31 24 54 / 98%));
    border-color: var(--color-gold-light);
    transform: translateY(-1px);
}

.button:active,
.btn:active {
    transform: none;
}

/* --primary is the one call to action a screen is allowed. It differs from the
   base only in size and in the brighter brass, because the mockup's hero pair
   — field plus button — has to read as one control. */
.button--primary,
.btn--primary {
    min-height: 57px;
    font-size: var(--text-base);
    color: var(--color-gold-bright);
    border-color: var(--color-gold-light);
}

/* --secondary is the base button under an explicit name, for templates that
   want to say "not the primary one" rather than rely on the default. */
.button--secondary,
.btn--secondary {
    color: var(--color-accent-text);
}

/* --ghost drops the plate and keeps the type: for the third and fourth action
   in a row, where four filled buttons would be four competing offers. */
.button--ghost,
.btn--ghost {
    color: var(--color-muted);
    background: transparent;
    border-color: var(--color-border-soft);
    box-shadow: none;
}

.button--ghost:hover,
.btn--ghost:hover {
    color: var(--color-gold-light);
    background: rgb(119 67 125 / 12%);
    border-color: var(--color-border);
}

/* --link is a button element that has to look like prose, for "Zrušit" next to
   a submit. Still 42px tall, because it is still a tap target. */
.button--link,
.btn--link {
    padding-inline: var(--space-2);
    font-size: var(--text-sm);
    font-weight: 550;
    color: var(--color-accent-text);
    text-transform: none;
    letter-spacing: 0.02em;
    background: none;
    border-color: transparent;
    box-shadow: none;
}

.button--link:hover,
.btn--link:hover {
    color: var(--color-gold-bright);
    background: none;
    border-color: transparent;
    transform: none;
}

/* --danger for destructive confirmations only. Red enough to hesitate over,
   not red enough to leave the palette. */
.button--danger,
.btn--danger {
    color: var(--color-danger);
    background: linear-gradient(180deg, rgb(64 22 30 / 92%), rgb(30 13 22 / 96%));
    border-color: rgb(229 128 121 / 55%);
}

.button--danger:hover,
.btn--danger:hover {
    color: #f6b3ad;
    background: linear-gradient(180deg, rgb(92 30 40 / 94%), rgb(42 17 28 / 98%));
    border-color: rgb(229 128 121 / 85%);
}

.button--small,
.btn--sm {
    min-height: 42px;
    padding-inline: 12px;
    font-size: var(--text-2xs);
}

.button--lg,
.btn--lg {
    min-height: 57px;
    font-size: var(--text-base);
}

/* The mockup's card CTA: a fixed narrow plate that never grows past its label. */
.reading-card .button--small,
.reading-card .btn--sm {
    width: min(119px, 100%);
    margin-block-start: auto;
}

.button--block,
.btn--block {
    display: flex;
    width: 100%;
}

.button[aria-disabled='true'],
.btn[aria-disabled='true'],
.button:disabled,
.btn:disabled {
    color: var(--color-muted);
    cursor: not-allowed;
    border-color: var(--color-border-soft);
    box-shadow: none;
    opacity: 0.55;
}

.button[aria-disabled='true']:hover,
.btn[aria-disabled='true']:hover,
.button:disabled:hover,
.btn:disabled:hover {
    color: var(--color-muted);
    background: linear-gradient(180deg, #2a1642, #190e30);
    border-color: var(--color-border-soft);
    transform: none;
}

/* =============================================================================
   Labels — eyebrow, section label, overline

   Three names for one typographic device (small brass capitals over a
   heading), kept apart because they differ in what decorates them:
   `.eyebrow` is bare, `.section-label` carries arrows or a rule, `.overline`
   is the name the existing subpages use and behaves like `.eyebrow`.
   ============================================================================= */

.eyebrow,
.section-label,
.overline,
.reading-card__kind,
.card__eyebrow {
    font-size: var(--text-sm);
    font-weight: 630;
    line-height: 1.3;
    color: var(--color-accent-text);
    text-transform: uppercase;
    letter-spacing: 0.18em;
}

.eyebrow span,
.overline span {
    padding-inline: 3px;
    font-size: 9px;
}

/* Centred, with the mockup's flanking arrows if the template supplies them. */
.section-label {
    display: flex;
    gap: 10px;
    align-items: center;
    justify-content: center;
}

.section-label span[aria-hidden='true'] {
    color: rgb(184 128 66 / 48%);
    letter-spacing: 0;
}

/* Left-aligned with a 31px brass rule in front — the mark every service row
   and every subpage `.page-head` wears. */
.section-label--left {
    gap: 11px;
    justify-content: flex-start;
}

.section-label--left::before {
    width: 31px;
    height: 1px;
    background: var(--color-gold);
    content: '';
}

.overline--centered {
    display: flex;
    gap: 10px;
    align-items: center;
    justify-content: center;
}

/* =============================================================================
   Site header (public)
   ============================================================================= */

.site-header {
    position: relative;
    z-index: 20;
    height: 88px;
    background-color: #050913;
    background-image: url("../images/header-left-Ovr6KQ-.png"), url("../images/header-right-GHbjpDg.png");
    background-repeat: no-repeat;
    background-position: left top, right top;
    background-size: 290px 115px, 220px 115px;
    border-bottom: 1px solid rgb(154 104 54 / 58%);
}

.site-header__inner {
    position: relative;
    display: flex;
    gap: 38px;
    align-items: center;
    justify-content: space-between;
    width: min(100% - 48px, var(--header-width));
    height: 100%;
    margin-inline: auto;
}

/* The logotype is a background image and the link's text is visually hidden,
   because symfony/asset is not installed and a template therefore has no
   asset() with which to name the hashed file — while AssetMapper does rewrite
   every url() it finds in a stylesheet. The accessible name is the link text
   itself, which is why the <span> inside is hidden rather than absent. */
.brand {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    width: 260px;
    height: 65px;
    background-image: url("../images/logo-hBqA6Iy.png");
    background-repeat: no-repeat;
    background-position: left center;
    background-size: contain;
    transform: translateX(-15px);
}

/* The wordmark fallback: the sigil plus the name, for the app and admin chrome
   where the full 260px logotype would crowd a dense toolbar. */
.brand__word {
    font-family: var(--font-serif);
    font-size: var(--text-xl);
    font-weight: 430;
    letter-spacing: 0.08em;
    color: var(--color-text);
}

.brand__mark {
    color: var(--color-gold);
}

.main-nav {
    display: flex;
    gap: 40px;
    align-items: center;
    justify-content: flex-end;
    min-width: 0;
}

.main-nav__link {
    position: relative;
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    font-size: var(--text-base);
    font-weight: 520;
    line-height: 1;
    color: #d9d6d4;
    text-transform: uppercase;
    white-space: nowrap;
    letter-spacing: 0.04em;
    transition: color var(--transition-fast);
}

.main-nav__link:hover,
.main-nav__link--active,
.main-nav__link[aria-current='page'] {
    color: var(--color-accent-text);
}

/* The current item wears a brass frame with a lit lower edge, drawn with two
   masked gradients rather than a border so the frame can fade at both ends.
   Verbatim from the mockup — this is the one ornament on the page that is
   pure decoration, and it is what makes the header look milled rather than
   printed.

   The same frame lights the „Výklady ▾" mega trigger while its `<details>` is
   `[open]`, and marks it as the current item on any page that is itself one of
   its services (`.mega__trigger[aria-current='page']`) — so the ornament that
   was only ever a mockup detail is now what tells you where in the shop you are
   standing. */
.main-nav__link--active,
.main-nav__link[aria-current='page'],
.mega[open] > .mega__trigger,
.mega__trigger[aria-current='page'] {
    min-height: 40px;
    padding-inline: 11.5px;
}

.main-nav__link--active::before,
.main-nav__link[aria-current='page']::before,
.mega[open] > .mega__trigger::before,
.mega__trigger[aria-current='page']::before {
    position: absolute;
    inset: 0 -1px 2px 0.5px;
    padding: 1px;
    background:
        linear-gradient(90deg,
            rgb(50 39 38) 0%,
            rgb(70 52 45) 5%,
            rgb(115 82 58) 17%,
            rgb(201 143 90) 30%,
            rgb(233 177 114) 37%,
            rgb(245 196 121) 42%,
            rgb(245 204 128) 58%,
            rgb(220 167 104) 69%,
            rgb(142 104 73) 82%,
            rgb(40 32 34) 100%) bottom / 100% 0.5px no-repeat,
        linear-gradient(rgb(5 8 18 / 40%), rgb(5 8 18 / 40%)) bottom / 100% 1px no-repeat,
        linear-gradient(90deg,
            rgb(112 72 42 / 20%) 0%,
            rgb(151 101 60 / 38%) 16%,
            rgb(190 133 79 / 62%) 32%,
            rgb(213 158 99 / 78%) 50%,
            rgb(198 140 84 / 73%) 68%,
            rgb(151 101 60 / 46%) 84%,
            rgb(112 72 42 / 18%) 100%);
    border-radius: var(--radius-sm);
    mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    mask-composite: exclude;
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    pointer-events: none;
    content: '';
}

.main-nav__link--active::after,
.main-nav__link[aria-current='page']::after,
.mega[open] > .mega__trigger::after,
.mega__trigger[aria-current='page']::after {
    position: absolute;
    inset-block-start: 33px;
    inset-inline-start: calc(50% + 1.5px);
    width: 22px;
    height: 9px;
    background:
        linear-gradient(90deg, transparent 0%, rgb(199 125 58 / 14%) 27%, rgb(255 221 160 / 76%) 45%, #fff8df 50%, rgb(255 221 160 / 76%) 55%, rgb(199 125 58 / 14%) 73%, transparent 100%) center / 100% 1px no-repeat,
        linear-gradient(180deg, transparent 0%, rgb(206 132 62 / 12%) 19%, rgb(255 218 153 / 78%) 43%, #fff9e6 50%, rgb(255 218 153 / 72%) 57%, rgb(206 132 62 / 18%) 77%, transparent 100%) center / 1px 100% no-repeat,
        radial-gradient(ellipse 24% 50% at center, rgb(255 245 213 / 96%) 0 8%, rgb(240 169 90 / 36%) 42%, transparent 100%);
    transform: translateX(-50%);
    pointer-events: none;
    content: '';
}

.button--header,
.btn--header {
    min-width: 161px;
    min-height: 44px;
    width: 161px;
    margin-inline-start: 3px;
    padding-inline: 12px;
    font-size: 14px;
    white-space: nowrap;
}

/* --- „Výklady" mega-menu: one <details>, every service, no JavaScript ----- *
 * The disclosure that replaced the flat nav. The trigger is a <summary>; the
 * panel is anchored to the header, not to the trigger, so it opens centred
 * under the bar whether the trigger sits on the right of the public row or at
 * the head of the signed-in tool-bar. Above 1180px only; below it the trigger
 * lives inside a `.main-nav`/`.site-nav` that CSS has hidden, and the same
 * grouped links are stacked into the `.mobile-nav__panel` instead — so a phone
 * never shows both a wide nav and a hamburger.
 *
 * `.mega` itself is intentionally left `position: static`: the panel's offset
 * parent is then the positioned header inner (`.site-header__inner` is already
 * relative; `.app-header__inner` is made so below), which is what lets a panel
 * far wider than the trigger stay inside the viewport at every width. */
.mega {
    display: inline-flex;
    align-items: center;
}

.mega__trigger {
    position: relative;
    display: inline-flex;
    gap: 6px;
    align-items: center;
    min-height: 40px;
    padding-inline: 11.5px;
    font-size: var(--text-base);
    font-weight: 520;
    line-height: 1;
    color: #d9d6d4;
    text-transform: uppercase;
    white-space: nowrap;
    letter-spacing: 0.04em;
    cursor: pointer;
    list-style: none;
    transition: color var(--transition-fast);
}

.mega__trigger::-webkit-details-marker {
    display: none;
}

.mega__trigger:hover,
.mega[open] > .mega__trigger {
    color: var(--color-accent-text);
}

/* The caret is drawn, not typed — the same chevron the account chip wears, for
   the same reason: a glyph would need a font that has one and sits where this
   one does. */
.mega__caret {
    flex: 0 0 auto;
    width: 6px;
    height: 6px;
    border-right: 1px solid currentcolor;
    border-bottom: 1px solid currentcolor;
    transform: translateY(-2px) rotate(45deg);
    transition: transform var(--transition-fast);
}

.mega[open] > .mega__trigger .mega__caret {
    transform: translateY(1px) rotate(-135deg);
}

.mega__panel {
    position: absolute;
    inset-block-start: calc(100% + 1px);
    inset-inline: 0;
    z-index: 45;
    width: min(1120px, calc(100vw - 32px));
    padding: 22px 26px 24px;
    margin-inline: auto;

    /* Opaque, like the account menu and for the same reason: it opens over the
       hero art of whatever page somebody is standing on, and a menu you can
       read the page through is not a menu. */
    background: var(--color-background-deep);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    box-shadow: 0 22px 60px rgb(0 0 0 / 55%);
}

/* Four columns, reading left to right, seven categories across two rows. The
   short groups leave space beneath them rather than forcing a tall row — the
   standard mega-menu trade, and the one that keeps the reading order intact. */
.mega__grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 20px 24px;
    align-items: start;
}

.mega__label {
    margin-block-end: 9px;
}

.mega__list {
    display: grid;
    gap: 2px;
    padding: 0;
    margin: 0;
    list-style: none;
}

.mega__link {
    display: block;
    padding: 7px 9px;
    font-size: 13px;
    font-weight: 500;
    color: var(--color-text-soft);
    letter-spacing: 0.01em;
    border-radius: var(--radius-sm);
    transition: color var(--transition-fast), background var(--transition-fast);
}

.mega__link:hover,
.mega__link[aria-current='page'] {
    color: var(--color-accent-text);
    background: rgb(119 67 125 / 12%);
}

/* In the signed-in tool-bar the trigger is one dense item among many, so it is
   scaled to sit beside `.site-nav__link` rather than beside a public
   `.main-nav__link`. It still grows to wear the brass frame when open — the
   frame's own rule outranks this one — which is the few pixels of movement the
   ornament is worth. */
.site-nav .mega__trigger {
    min-height: 34px;
    padding-inline: var(--space-2);
    font-size: var(--text-xs);
    font-weight: 550;
    letter-spacing: 0.08em;
}

/* --- Mobile navigation: a <details>, no JavaScript ----------------------- *
 * A disclosure element is the whole mechanism. It survives a Turbo navigation
 * (the header is re-rendered closed, which is what anyone would expect), works
 * with the keyboard for free, and cannot get stuck open because a controller
 * failed to load.                                                            */
.mobile-nav {
    display: none;
}

/* =============================================================================
   Site footer (public)
   ============================================================================= */

/* `overflow: hidden` because the motto's two flanking rules are positioned from
   the centre outwards (`calc(50% + 385px)`) and run past the viewport between
   about 900 and 1400px. `body { overflow-x: hidden }` already stops that from
   producing a scrollbar, but a page whose scrollWidth is wider than its
   viewport is one refactor away from being one that scrolls sideways. */
.site-footer {
    position: relative;
    overflow: hidden;
    padding: var(--space-6) var(--space-5) var(--space-7);
    text-align: center;
    border-top: 1px solid var(--color-border-soft);
}

.site-footer__motto {
    position: relative;
    padding-block-start: 4px;
    font-size: 10px;
    font-weight: 620;
    line-height: 1.5;
    color: var(--color-accent-text);
    text-transform: uppercase;
    letter-spacing: 0.24em;
}

.site-footer__motto::before,
.site-footer__motto::after {
    position: absolute;
    inset-block-start: 12px;
    width: min(22vw, 430px);
    height: 1px;
    background: var(--rule-gold-fade);
    content: '';
}

.site-footer__motto::before {
    inset-inline-end: calc(50% + 385px);
}

.site-footer__motto::after {
    inset-inline-start: calc(50% + 385px);
    transform: scaleX(-1);
}

.site-footer__motto span {
    margin-inline: 20px;
    color: rgb(205 151 84 / 60%);
}

.site-footer__inner {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4) var(--space-6);
    align-items: center;
    justify-content: center;
    margin-block-start: var(--space-5);
    font-size: var(--text-sm);
    color: var(--color-muted);
}

.site-footer__brand {
    display: inline-flex;
    gap: var(--space-2);
    align-items: center;
    font-family: var(--font-serif);
    font-size: var(--text-md);
    color: var(--color-text);
}

.footer-nav {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-5);
    justify-content: center;
}

.footer-nav a {
    font-size: var(--text-sm);
    color: var(--color-muted);
    transition: color var(--transition-fast);
}

.footer-nav a:hover {
    color: var(--color-gold-light);
}

/* The sentence spec sec. 130 requires on every public page. Small because it
   is a standing qualification and not a warning; a banner would be theatre. */
.site-footer__disclaimer {
    max-width: 78ch;
    margin-block-start: var(--space-5);
    margin-inline: auto;
    font-size: var(--text-xs);
    line-height: 1.7;
    color: var(--color-muted);
    text-align: center;
}

/* =============================================================================
   App chrome (signed in) and admin chrome

   Both are the public header with the ornament turned down: the same brass
   rule, the same type, no bleeding illustration. The signed-in navigation
   carries eleven items and the admin nine, and neither survives being drawn
   the way the seven-item public nav is.
   ============================================================================= */

.app-header {
    position: relative;
    z-index: 20;
    background-color: #050913;
    border-bottom: 1px solid rgb(154 104 54 / 58%);
}

.app-header__inner {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4) var(--space-5);
    align-items: center;
    justify-content: space-between;
    width: min(100% - 40px, var(--content-wide));
    min-height: 72px;
    padding-block: var(--space-3);
    margin-inline: auto;
}

.app-header .brand,
.admin-header .brand {
    width: 180px;
    height: 45px;
    transform: none;
}

/* The signed-in nav. Smaller and denser than `.main-nav`; it is a tool bar for
   somebody who already bought something, not a shop window. */
.site-nav {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-4);
    align-items: center;
    min-width: 0;
}

.site-nav__link {
    display: inline-flex;
    gap: var(--space-2);
    align-items: center;
    min-height: 38px;
    padding-inline: var(--space-2);
    font-size: var(--text-xs);
    font-weight: 550;
    color: #d9d6d4;
    text-transform: uppercase;
    white-space: nowrap;
    letter-spacing: 0.08em;
    border-radius: var(--radius-sm);
    transition: color var(--transition-fast), background var(--transition-fast);
}

.site-nav__link:hover {
    color: var(--color-accent-text);
    background: rgb(119 67 125 / 12%);
}

.site-nav__link[aria-current='page'] {
    color: var(--color-accent-text);
    box-shadow: inset 0 -1px 0 var(--color-gold);
}

/* Eleven nav items, a logotype and an e-mail address do not fit on one line
   below a very wide desktop. Rather than let the row wrap wherever it likes —
   which drops the user chip to the left of a second row, under nothing — the
   nav is given a row of its own and the brand and the chip keep the first. */
@media (max-width: 90rem) {
    .app-header__inner {
        row-gap: var(--space-2);
    }

    .app-header__inner .site-nav {
        order: 3;
        flex-basis: 100%;
        padding-block-end: var(--space-1);
    }
}

.user-chip {
    display: inline-flex;
    gap: var(--space-2);
    align-items: center;
    max-width: 260px;
    min-height: 38px;
    padding: 0 var(--space-3) 0 var(--space-2);
    overflow: hidden;
    font-size: var(--text-xs);
    color: var(--color-muted);
    text-overflow: ellipsis;
    white-space: nowrap;
    border: 1px solid var(--color-border-soft);
    border-radius: var(--radius-pill);
    transition: color var(--transition-fast), border-color var(--transition-fast);
}

a.user-chip:hover {
    color: var(--color-text);
    border-color: var(--color-border);
}

.user-chip__avatar {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    flex: 0 0 auto;
    place-items: center;
    width: 26px;
    height: 26px;
    font-size: var(--text-2xs);
    font-weight: 650;
    color: var(--color-text-inverse);
    background: linear-gradient(160deg, var(--color-gold-light), var(--color-gold));
    border-radius: 50%;
}

/* The signed-in visitor's menu. The chip is the <summary>, the panel is what the
   <details> discloses — the same mechanism `.mobile-nav` uses, for the same
   reason: CSP is enforced with a per-request nonce, so there is no inline
   script, and a Stimulus controller loaded on every page to toggle one
   attribute is not worth writing.

   Opening this does not close the mobile menu and vice versa — closing a
   sibling <details> needs script. The two panels do not overlap and either
   closes on its own summary, so the cost is cosmetic. */
.user-menu {
    position: relative;
    flex: 0 0 auto;
}

.user-menu__chip {
    max-width: none;
    cursor: pointer;
    list-style: none;
}

.user-menu__chip::-webkit-details-marker {
    display: none;
}

.user-menu__chip:hover,
.user-menu[open] > .user-menu__chip {
    color: var(--color-text);
    border-color: var(--color-border);
}

.user-menu__balance {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Drawn rather than typed: a chevron glyph needs a font that has one and sits on
   the baseline instead of the optical centre of a 38px pill. */
.user-menu__chevron {
    flex: 0 0 auto;
    width: 6px;
    height: 6px;
    margin-inline-start: 3px;
    border-right: 1px solid currentcolor;
    border-bottom: 1px solid currentcolor;
    transform: translateY(-2px) rotate(45deg);
    transition: transform var(--transition-fast);
}

.user-menu[open] .user-menu__chevron {
    transform: translateY(1px) rotate(-135deg);
}

/* Right-aligned and clamped to the viewport, because the chip is the last thing
   in the header and a panel that opens leftwards from it would leave the
   screen at 320px. */
.user-menu__panel {
    position: absolute;
    inset-block-start: calc(100% + 10px);
    inset-inline-end: 0;
    z-index: 45;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 2px;
    width: min(276px, calc(100vw - 32px));
    padding: 12px;

    /* Opaque, unlike `.mobile-nav__panel`s 98%. That panel only ever opens over
       the top of a page; this one opens over the hero art of whatever public
       page somebody is standing on, and a menu you can read the page through is
       not a menu. */
    background: var(--color-background-deep);
    border: 1px solid var(--color-border);
    border-radius: 9px;
    box-shadow: 0 18px 50px rgb(0 0 0 / 48%);
}

.user-menu__who {
    padding: 0 12px 9px;
    overflow: hidden;
    font-size: var(--text-2xs);
    color: var(--color-muted);
    text-overflow: ellipsis;
    white-space: nowrap;
    border-bottom: 1px solid var(--color-border-soft);
}

.user-menu__item {
    display: flex;
    gap: var(--space-2);
    align-items: center;
    justify-content: space-between;
    min-height: 41px;
    padding-inline: 12px;
    font-size: 12px;
    font-weight: 550;
    color: var(--color-text-soft);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    border-radius: var(--radius-sm);
}

/* The hover wash is `.mobile-nav__panel`s, to the percent: two panels that open
   from the same header have to answer a pointer the same way. */
.user-menu__item:hover,
.user-menu__item[aria-current='page'] {
    color: var(--color-accent-text);
    background: rgb(119 67 125 / 12%);
}

/* „Kouzla" and „Dobít" are one line and two destinations, so they cannot be one
   anchor. */
.user-menu__row {
    display: flex;
    gap: var(--space-2);
    align-items: center;
}

.user-menu__row .user-menu__item {
    flex: 1 1 auto;
    min-width: 0;
}

.user-menu__value {
    font-size: var(--text-2xs);
    font-weight: 500;
    color: var(--color-gold-light);
    text-transform: none;
    white-space: nowrap;
    letter-spacing: 0.02em;
    font-variant-numeric: tabular-nums;
}

.user-menu__topup {
    flex: 0 0 auto;
    padding: 5px 11px;
    font-size: var(--text-2xs);
    font-weight: 620;
    color: var(--color-accent-text);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    border: 1px solid var(--color-border-soft);
    border-radius: var(--radius-pill);
    transition: color var(--transition-fast), border-color var(--transition-fast);
}

.user-menu__topup:hover {
    color: var(--color-gold-bright);
    border-color: var(--color-border);
}

.user-menu__item--out {
    margin-block-start: 7px;
    color: var(--color-muted);
    border-top: 1px solid var(--color-border-soft);
    border-radius: 0;
}

/* --- Admin --------------------------------------------------------------- */

.admin-header {
    background-color: var(--color-background-deep);
    border-bottom: 1px solid var(--color-border-soft);
}

.admin-header__inner {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3) var(--space-5);
    align-items: center;
    justify-content: space-between;
    min-height: 56px;
    padding-block: var(--space-2);
}

.admin-brand {
    font-family: var(--font-serif);
    font-size: var(--text-lg);
    letter-spacing: 0.04em;
    color: var(--color-text);
}

.admin-brand span {
    font-family: var(--font-sans);
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.16em;
    color: var(--color-muted);
}

.admin-whoami {
    display: flex;
    gap: var(--space-4);
    align-items: center;
    font-size: var(--text-xs);
    color: var(--color-muted);
}

/* The administration is dense on purpose: `is-admin` widens the measure, drops
   the star field (a data table on a starfield is a joke at the reader's
   expense) and tightens the base size by one step. */
.is-admin {
    --sky: none;
    --stack-space: var(--space-4);

    font-size: var(--text-base);
}

.is-admin .container {
    width: min(100% - 2 * var(--space-5), var(--content-wide));
}

.admin-shell {
    display: grid;
    grid-template-columns: 180px minmax(0, 1fr);
    gap: var(--space-6);
    align-items: start;
    padding-block: var(--space-6);
}

.admin-rail__list {
    position: sticky;
    inset-block-start: var(--space-5);
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 2px;
    padding: 0;
    margin: 0;
    list-style: none;
}

.admin-rail__link {
    display: block;
    padding: var(--space-2) var(--space-3);
    font-size: var(--text-sm);
    font-weight: 550;
    color: var(--color-muted);
    border-radius: var(--radius-sm);
    transition: color var(--transition-fast), background var(--transition-fast);
}

.admin-rail__link:hover {
    color: var(--color-text);
    background: rgb(119 67 125 / 12%);
}

.admin-rail__link.is-current {
    color: var(--color-accent-text);
    background: rgb(200 145 76 / 10%);
    box-shadow: inset 2px 0 0 var(--color-gold);
}

@media (width < 62rem) {
    .admin-shell {
        grid-template-columns: minmax(0, 1fr);
        gap: var(--space-4);
    }

    .admin-rail__list {
        position: static;
        display: flex;
        flex-wrap: wrap;
        gap: var(--space-1);
    }

    .admin-rail__link.is-current {
        box-shadow: inset 0 -2px 0 var(--color-gold);
    }
}

.admin-main h2 {
    font-size: var(--text-xl);
}

.admin-main h3 {
    font-size: var(--text-lg);
}

.admin-head {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-4);
    align-items: baseline;
    justify-content: space-between;
    padding-block-end: var(--space-3);
    border-bottom: 1px solid var(--color-border-soft);
}

.admin-head h1 {
    font-size: var(--text-2xl);
}

.admin-head__note {
    font-size: var(--text-sm);
    color: var(--color-muted);
}

.admin-notice {
    padding: var(--space-3) var(--space-4);
    font-size: var(--text-sm);
    color: var(--color-text-soft);
    background: rgb(200 145 76 / 8%);
    border: 1px solid var(--color-border-soft);
    border-radius: var(--radius-sm);
}

.admin-notice strong {
    color: var(--color-gold-light);
}

.admin-filters {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    align-items: flex-end;
}

.admin-facts {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    gap: var(--space-2) var(--space-4);
    font-size: var(--text-sm);
}

.admin-facts dt {
    color: var(--color-muted);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    font-size: var(--text-2xs);
    align-self: center;
}

.admin-facts dd {
    margin: 0;
    color: var(--color-text);
}

.admin-pre {
    max-height: 26rem;
    padding: var(--space-4);
    overflow: auto;
    font-size: var(--text-xs);
    line-height: 1.7;
    color: var(--color-text-soft);
    white-space: pre-wrap;
    background: var(--color-background-deep);
    border: 1px solid var(--color-border-soft);
    border-radius: var(--radius-sm);
}

/* =============================================================================
   Page head — the top of every subpage

   `.page-head` is the derived counterpart of the mockup's `.tarot__heading`:
   a brass label, a Fraunces h1 and a lede. Left-aligned by default because
   most subpages are documents; `--centered` for the few that are posters.
   ============================================================================= */

.page-head {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-3);
    padding-block-end: var(--space-5);
}

.page-head--centered {
    justify-items: center;
    text-align: center;
}

.page-head__title,
.page-title {
    font-family: var(--font-serif);
    font-size: var(--text-3xl);
    font-weight: 390;
    line-height: 1.16;
    letter-spacing: -0.02em;
}

.page-head__lead,
.page-head__lede {
    max-width: 62ch;
    font-size: var(--text-md);
    line-height: 1.8;
    color: var(--color-text-soft);
}

/* The existing subpage vocabulary for the same thing. Kept, because it is used
   on more than a hundred templates and renaming it would be a refactor rather
   than a redesign. */
.section-header {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-3);
}

.section-header--centered {
    justify-items: center;
    text-align: center;
}

.section-header__title {
    font-family: var(--font-serif);
    font-size: var(--text-2xl);
    font-weight: 390;
    line-height: 1.16;
    letter-spacing: -0.02em;
}

.section-header__lede {
    max-width: 64ch;
    font-size: var(--text-base);
    line-height: 1.75;
    color: var(--color-text-soft);
}

.section-title {
    font-family: var(--font-serif);
    font-size: var(--text-xl);
    font-weight: 400;
}

/* =============================================================================
   Panel and card — the two raised surfaces

   `.panel` is the page-level container: a framed plate that holds a form, a
   table, a block of prose. `.card` is the same object at item scale, in a grid
   of siblings. They share the fill and the frame so the page looks milled from
   one material.
   ============================================================================= */

.panel,
.card {
    padding: var(--space-5);
    background: var(--plate-fill);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--plate-shadow);
}

.panel--quiet,
.card--quiet,
.card--muted {
    background: var(--plate-fill-soft);
    border-color: var(--color-border-soft);
}

.panel--flush {
    padding: 0;
    overflow: hidden;
}

.card {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.card__title {
    font-family: var(--font-serif);
    font-size: var(--text-xl);
    font-weight: 400;
    line-height: 1.2;
}

.card__body {
    font-size: var(--text-base);
    line-height: 1.75;
    color: var(--color-text-soft);
}

.card__footer {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    align-items: center;
    margin-block-start: auto;
    padding-block-start: var(--space-2);
}

.card__eyebrow {
    font-size: var(--text-xs);
}

/* Several of the containers below are grid or column-flex, so a button placed
   directly in one would stretch to the container's width and become a bar. A
   button is sized by its label everywhere else in the system and has to be here
   too; `.button--block` is the opt-in for the cases that really do want the
   full width (a submit at the foot of a narrow form).

   `:where()` keeps the specificity at zero so any component can still say
   otherwise in one line. */
:where(.card, .price-card, .panel, .account-fact, .form-field, .field, .notice)
    > :is(.button, .btn):not(.button--block, .btn--block) {
    align-self: start;
    justify-self: start;
}

/* A card that is itself a link, or holds one, lifts on hover. */
a.card,
.card--link,
.card--reading {
    transition: border-color var(--transition-fast), transform var(--transition-fast);
}

a.card:hover,
.card--link:hover,
.card--reading:hover {
    border-color: var(--color-gold-light);
    transform: translateY(-2px);
}

/* A read notification steps back rather than disappearing: the row is still
   there, it just stops asking for attention. */
.notification--read .card__body,
.notification--read .card__eyebrow {
    color: var(--color-muted);
    opacity: 0.75;
}

/* =============================================================================
   Notice and empty state
   ============================================================================= */

.notice {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-2);
    padding: var(--space-4);
    font-size: var(--text-base);
    line-height: 1.7;
    color: var(--color-text-soft);
    background: rgb(200 145 76 / 7%);
    border: 1px solid var(--color-border-soft);
    border-inline-start: 2px solid var(--color-gold);
    border-radius: var(--radius-sm);
}

.notice--warning {
    background: rgb(224 168 91 / 9%);
    border-inline-start-color: var(--color-warning);
}

.notice--danger {
    background: rgb(229 128 121 / 9%);
    border-inline-start-color: var(--color-danger);
}

/* `.kn-empty` is the apology an unseeded catalogue prints. It was a plate of
   its own in pages/knowledge.css and is the same object: a dashed frame with a
   sentence in it. */
.empty-state,
.empty,
.kn-empty {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-3);
    place-items: center;
    padding: var(--space-7) var(--space-5);
    font-size: var(--text-base);
    color: var(--color-muted);
    text-align: center;
    border: 1px dashed var(--color-border-soft);
    border-radius: var(--radius);
}

/* `.acct-empty__title` is the same line under the name eight account templates
   already carry. The measure and the line-height came with it: an invitation is
   allowed two lines and they have to sit close. */
.empty-state__title,
.acct-empty__title {
    max-width: 46ch;
    font-family: var(--font-serif);
    font-size: var(--text-xl);
    font-weight: 400;
    line-height: 1.3;
    color: var(--color-text);
}

/* =============================================================================
   Dividers
   ============================================================================= */

.divider,
.rule {
    height: 1px;
    border: 0;
    background: var(--rule-gold);
}

.divider--short {
    width: min(100%, 240px);
    margin-inline: auto;
}

/* =============================================================================
   Forms

   `.form-field` is the canonical wrapper; `.field` is the same thing under the
   name the existing templates use. Inside either, `.input`, `.select` and
   `.textarea` are the controls, `.label` the caption, `.field__help` the note
   under it and `.field__error` the failure.

   The control styling is the mockup's hero field, which is the only input the
   design was delivered with: a cool near-black gradient with a neutral border
   that turns brass on focus.
   ============================================================================= */

.form-field,
.field {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-2);
}

.form-field--inline,
.field--inline {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: end;
}

.label,
.form-field__label,
.field__label {
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--color-text-soft);
    text-transform: uppercase;
    letter-spacing: 0.12em;
}

.label__optional {
    font-weight: 400;
    text-transform: none;
    letter-spacing: 0;
    color: var(--color-muted);
}

.input,
.select,
.textarea,
input[type='text'],
input[type='email'],
input[type='password'],
input[type='search'],
input[type='url'],
input[type='tel'],
input[type='number'],
input[type='date'],
input[type='time'],
input[type='datetime-local'],
select,
textarea {
    width: 100%;
    min-height: 46px;
    padding: 11px 16px;
    font-family: var(--font-sans);
    font-size: var(--text-base);
    color: var(--color-text);
    background: linear-gradient(100deg, rgb(28 29 40 / 96%), rgb(19 21 33 / 94%));
    border: 1px solid var(--color-border-neutral);
    border-radius: var(--radius-control);
    box-shadow: inset 0 0 20px rgb(255 255 255 / 1.5%);
    outline: none;
    transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.textarea,
textarea {
    min-height: 8rem;
    line-height: 1.7;
    resize: vertical;
}

.select,
select {
    padding-inline-end: var(--space-6);
    appearance: none;
    background-image:
        linear-gradient(45deg, transparent 50%, var(--color-gold) 50%),
        linear-gradient(135deg, var(--color-gold) 50%, transparent 50%),
        linear-gradient(100deg, rgb(28 29 40 / 96%), rgb(19 21 33 / 94%));
    background-position:
        calc(100% - 20px) calc(50% + 1px),
        calc(100% - 15px) calc(50% + 1px),
        0 0;
    background-size: 5px 5px, 5px 5px, 100% 100%;
    background-repeat: no-repeat;
}

.input:focus,
.select:focus,
.textarea:focus,
input:focus,
select:focus,
textarea:focus {
    border-color: var(--color-gold-light);
    box-shadow: 0 0 0 1px rgb(224 175 103 / 35%), inset 0 0 20px rgb(255 255 255 / 2%);
}

.input:disabled,
.select:disabled,
.textarea:disabled,
input:disabled,
select:disabled,
textarea:disabled {
    color: var(--color-muted);
    cursor: not-allowed;
    opacity: 0.6;
}

/* Checkbox and radio: the browser's own control, tinted. A hand-drawn one
   would be four rules of CSS and one accessibility regression. */
input[type='checkbox'],
input[type='radio'] {
    width: 1.05rem;
    height: 1.05rem;
    min-height: 0;
    padding: 0;
    accent-color: var(--color-gold);
    cursor: pointer;
}

.field--check,
.form-field--check {
    grid-template-columns: auto minmax(0, 1fr);
    gap: var(--space-3);
    align-items: start;
}

.field--check .label,
.form-field--check .label {
    font-size: var(--text-base);
    font-weight: 400;
    text-transform: none;
    letter-spacing: 0;
    color: var(--color-text-soft);
}

/* A radio or checkbox with a label beside it, as one clickable plate. */
.choice,
.choices > label {
    display: flex;
    gap: var(--space-3);
    align-items: flex-start;
    padding: var(--space-3) var(--space-4);
    font-size: var(--text-base);
    line-height: 1.6;
    color: var(--color-text-soft);
    cursor: pointer;
    background: var(--plate-fill-soft);
    border: 1px solid var(--color-border-soft);
    border-radius: var(--radius-control);
    transition: border-color var(--transition-fast), background var(--transition-fast);
}

.choice:hover,
.choices > label:hover {
    border-color: var(--color-border);
}

.choice:has(input:checked),
.choices > label:has(input:checked) {
    color: var(--color-text);
    border-color: var(--color-gold-light);
    background: rgb(200 145 76 / 10%);
}

.choice:focus-within,
.choices > label:focus-within {
    outline: 2px solid var(--color-gold-light);
    outline-offset: 2px;
}

.choices {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-2);
}

.field__help,
.form-field__help {
    font-size: var(--text-sm);
    line-height: 1.65;
    color: var(--color-muted);
}

.field__error,
.form-field__error {
    display: flex;
    gap: var(--space-2);
    align-items: baseline;
    font-size: var(--text-sm);
    color: var(--color-danger);
}

.field__error::before,
.form-field__error::before {
    content: '✕';
    font-size: 0.8em;
}

.field--invalid .input,
.field--invalid .select,
.field--invalid .textarea,
.form-field--invalid .input,
.form-field--invalid .select,
.form-field--invalid .textarea {
    border-color: var(--color-danger);
}

.field--invalid .input:focus,
.field--invalid .select:focus,
.field--invalid .textarea:focus,
.form-field--invalid .input:focus {
    box-shadow: 0 0 0 1px rgb(229 128 121 / 40%);
}

/* A form's action row: submit on the left, escape hatches after it. */
.form-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    align-items: center;
    padding-block-start: var(--space-2);
}

/* =============================================================================
   Flash messages
   ============================================================================= */

.flash-stack {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-2);
    padding-block-start: var(--space-4);
}

.flash {
    display: flex;
    gap: var(--space-3);
    align-items: baseline;
    padding: var(--space-3) var(--space-4);
    font-size: var(--text-base);
    line-height: 1.6;
    color: var(--color-text);
    background: var(--plate-fill-soft);
    border: 1px solid var(--color-border-soft);
    border-inline-start: 2px solid var(--color-gold);
    border-radius: var(--radius-sm);
}

.flash::before {
    flex: 0 0 auto;
    font-size: 0.9em;
    color: var(--color-gold);
    content: '✦';
}

.flash--success {
    border-inline-start-color: var(--color-success);
}

.flash--success::before {
    color: var(--color-success);
    content: '✓';
}

.flash--warning,
.flash--notice {
    border-inline-start-color: var(--color-warning);
}

.flash--warning::before,
.flash--notice::before {
    color: var(--color-warning);
    content: '!';
}

.flash--error,
.flash--danger {
    border-inline-start-color: var(--color-danger);
}

.flash--error::before,
.flash--danger::before {
    color: var(--color-danger);
    content: '✕';
}

.flash--info {
    border-inline-start-color: var(--color-info);
}

.flash--info::before {
    color: var(--color-info);
    content: 'i';
}

/* =============================================================================
   Badges
   ============================================================================= */

.badge {
    display: inline-flex;
    gap: var(--space-1);
    align-items: center;
    padding: 3px 9px;
    font-size: var(--text-2xs);
    font-weight: 620;
    line-height: 1.4;
    color: var(--color-gold-light);
    text-transform: uppercase;
    white-space: nowrap;
    letter-spacing: 0.12em;
    background: rgb(200 145 76 / 12%);
    border: 1px solid var(--color-border-soft);
    border-radius: var(--radius-pill);
}

.badge--muted {
    color: var(--color-muted);
    background: rgb(170 166 164 / 10%);
    border-color: rgb(170 166 164 / 22%);
}

.badge--solid {
    color: var(--color-text-inverse);
    background: var(--color-gold-light);
    border-color: var(--color-gold-light);
}

.badge--copper {
    color: #e8a877;
    background: rgb(192 122 75 / 16%);
    border-color: rgb(192 122 75 / 40%);
}

.badge--success {
    color: var(--color-success);
    background: rgb(121 194 148 / 12%);
    border-color: rgb(121 194 148 / 32%);
}

.badge--warning {
    color: var(--color-warning);
    background: rgb(224 168 91 / 12%);
    border-color: rgb(224 168 91 / 32%);
}

.badge--danger {
    color: var(--color-danger);
    background: rgb(229 128 121 / 12%);
    border-color: rgb(229 128 121 / 32%);
}

/* =============================================================================
   Tables

   Every table lives inside `.table-scroll`. A data table has a minimum width
   below which it stops being readable, and the choice at 360px is between a
   table that scrolls in its own box and a page that scrolls sideways — the
   first is a table, the second is a bug.
   ============================================================================= */

.table-scroll {
    width: 100%;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    border: 1px solid var(--color-border-soft);
    border-radius: var(--radius-sm);
}

/* A scroll box inside a panel would draw a second frame one pixel inside the
   first. The panel is the frame; the box only needs to clip. */
.panel > .table-scroll,
.card > .table-scroll {
    border: 0;
    border-radius: 0;
}

.data-table {
    width: 100%;
    min-width: 34rem;
    font-size: var(--text-base);
    border-collapse: collapse;
}

.data-table th {
    padding: var(--space-3) var(--space-4);
    font-size: var(--text-2xs);
    font-weight: 620;
    color: var(--color-accent-text);
    text-align: start;
    text-transform: uppercase;
    white-space: nowrap;
    letter-spacing: 0.14em;
    background: rgb(9 12 25 / 90%);
    border-bottom: 1px solid var(--color-border-soft);
}

.data-table td {
    padding: var(--space-3) var(--space-4);
    color: var(--color-text-soft);
    vertical-align: top;
    border-bottom: 1px solid rgb(153 105 59 / 16%);
}

.data-table tbody tr:last-child td {
    border-bottom: 0;
}

.data-table tbody tr:hover td {
    background: rgb(200 145 76 / 5%);
}

.data-table--dense th,
.data-table--dense td {
    padding: var(--space-2) var(--space-3);
    font-size: var(--text-sm);
}

/* Numbers are tabular and right-aligned, so a column of amounts lines up on
   the decimal without a monospace font doing it by brute force. */
.data-table__num {
    font-variant-numeric: tabular-nums;
    text-align: end;
    white-space: nowrap;
}

.data-table__num--positive {
    color: var(--color-success);
}

.data-table__num--negative {
    color: var(--color-danger);
}

.data-table__when {
    font-size: var(--text-sm);
    color: var(--color-muted);
    white-space: nowrap;
}

.data-table .field__help {
    font-size: var(--text-xs);
}

/* =============================================================================
   Pager
   ============================================================================= */

.pager,
.admin-pager {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    align-items: center;
    justify-content: center;
    padding-block: var(--space-4);
    font-size: var(--text-sm);
    color: var(--color-muted);
}

.pager a,
.admin-pager a {
    display: inline-flex;
    align-items: center;
    min-height: 36px;
    padding-inline: var(--space-3);
    color: var(--color-accent-text);
    border: 1px solid var(--color-border-soft);
    border-radius: var(--radius-sm);
    transition: border-color var(--transition-fast), color var(--transition-fast);
}

.pager a:hover,
.admin-pager a:hover {
    color: var(--color-gold-bright);
    border-color: var(--color-border);
}

.pager__current {
    font-variant-numeric: tabular-nums;
}

/* =============================================================================
   Breadcrumbs
   ============================================================================= */

.breadcrumbs {
    font-size: var(--text-sm);
    color: var(--color-muted);
}

.breadcrumbs__list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    align-items: center;
    padding: 0;
    margin: 0;
    list-style: none;
}

.breadcrumbs__item {
    display: inline-flex;
    gap: var(--space-2);
    align-items: center;
}

.breadcrumbs__item + .breadcrumbs__item::before {
    color: rgb(184 128 66 / 55%);
    content: '›';
}

.breadcrumbs__item a {
    color: var(--color-muted);
    transition: color var(--transition-fast);
}

.breadcrumbs__item a:hover {
    color: var(--color-gold-light);
}

.breadcrumbs__item[aria-current='page'] {
    color: var(--color-text-soft);
}

/* =============================================================================
   Tabs and filter chips

   The same control at two jobs: `.tabs` switch a view, `.filter-chips` narrow
   a list. Identical to look at, which is correct — they behave identically too.
   ============================================================================= */

.tabs,
.admin-tabs,
.filter-chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    align-items: center;
    padding: 0;
    margin: 0;
    list-style: none;
}

.tabs a,
.admin-tabs a,
.filter-chip {
    display: inline-flex;
    align-items: center;
    min-height: 34px;
    padding-inline: var(--space-3);
    font-size: var(--text-xs);
    font-weight: 550;
    color: var(--color-muted);
    text-transform: uppercase;
    white-space: nowrap;
    letter-spacing: 0.1em;
    cursor: pointer;
    background: transparent;
    border: 1px solid var(--color-border-soft);
    border-radius: var(--radius-pill);
    transition: color var(--transition-fast), border-color var(--transition-fast), background var(--transition-fast);
}

.tabs a:hover,
.admin-tabs a:hover,
.filter-chip:hover {
    color: var(--color-text);
    border-color: var(--color-border);
}

.tabs a.is-current,
.admin-tabs a.is-current,
.filter-chip--active {
    color: var(--color-gold-bright);
    background: rgb(200 145 76 / 14%);
    border-color: var(--color-gold-light);
}

/* =============================================================================
   Steps — the numbered "jak to funguje" list

   The counter is drawn in Fraunces at display size and set in the margin, so
   the list reads as three plates rather than as an ordered list with a bigger
   font.
   ============================================================================= */

.steps {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    gap: var(--space-4);
    padding: 0;
    margin: 0;
    counter-reset: step;
    list-style: none;
}

.steps > li {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-2);
    align-content: start;
    padding: var(--space-5) var(--space-5) var(--space-5) calc(var(--space-5) + 2.6rem);
    counter-increment: step;
    background: var(--plate-fill);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--plate-shadow);
}

.steps > li::before {
    position: absolute;
    inset-block-start: calc(var(--space-5) - 0.35rem);
    inset-inline-start: var(--space-5);
    font-family: var(--font-serif);
    font-size: 2rem;
    font-weight: 300;
    line-height: 1;
    color: rgb(224 144 45 / 70%);
    content: counter(step);
}

.step__name {
    font-family: var(--font-serif);
    font-size: var(--text-lg);
    font-weight: 430;
    line-height: 1.25;
    color: var(--color-text);
}

.step__note {
    font-size: var(--text-base);
    line-height: 1.75;
    color: var(--color-muted);
}

/* =============================================================================
   KPI tiles
   ============================================================================= */

.kpi-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    gap: var(--space-3);
}

.kpi {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-1);
    padding: var(--space-4);
    background: var(--plate-fill-soft);
    border: 1px solid var(--color-border-soft);
    border-radius: var(--radius-sm);
}

.kpi__label {
    font-size: var(--text-2xs);
    font-weight: 620;
    color: var(--color-muted);
    text-transform: uppercase;
    letter-spacing: 0.14em;
}

.kpi__value {
    font-family: var(--font-serif);
    font-size: var(--text-2xl);
    font-weight: 400;
    line-height: 1.1;
    color: var(--color-text);
    font-variant-numeric: tabular-nums;
}

.kpi__value--positive {
    color: var(--color-success);
}

.kpi__value--negative {
    color: var(--color-danger);
}

.kpi__meta {
    font-size: var(--text-xs);
    color: var(--color-muted);
}

/* =============================================================================
   Price cards
   ============================================================================= */

.price-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    gap: var(--space-4);
}

.price-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-5);
    background: var(--plate-fill);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--plate-shadow);
}

.price-card__name {
    font-family: var(--font-serif);
    font-size: var(--text-xl);
    font-weight: 400;
    line-height: 1.2;
}

.price-card__amount {
    font-family: var(--font-serif);
    font-size: var(--text-2xl);
    font-weight: 390;
    line-height: 1.1;
    color: var(--color-gold-light);
    font-variant-numeric: tabular-nums;
}

.price-card__unit,
.price-card__credits {
    font-family: var(--font-sans);
    font-size: var(--text-xs);
    font-weight: 550;
    color: var(--color-muted);
    text-transform: uppercase;
    letter-spacing: 0.12em;
}

.price-card__note {
    font-size: var(--text-base);
    line-height: 1.7;
    color: var(--color-muted);
}

.price-card__cta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    align-items: center;
    margin-block-start: auto;
    padding-block-start: var(--space-3);
}

/* =============================================================================
   Card plates — a drawn tarot card, rune, hexagram or lenormand card

   The plate is the single most repeated object on the site and the one every
   functional test reaches for, so its class names are fixed:
   `.card-plate`, `__glyph`, `__name`, `__position`, `__orientation`,
   `__caption`, and the modifiers `--reversed`, `--drawn`, `--link`,
   `--doubtful`.
   ============================================================================= */

.card-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
    gap: var(--space-3);
    padding: 0;
    margin: 0;
    list-style: none;
}

.card-row--wide {
    grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
}

.card-row--index {
    grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr));
    gap: var(--space-2);
}

.card-plate {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-2);
    align-content: start;
    justify-items: center;
    padding: var(--space-4) var(--space-3);
    overflow: hidden;
    text-align: center;
    background: var(--plate-fill);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--plate-shadow);
}

/* A hairline inset, one pixel in from the frame — the engraved double rule the
   card illustrations in the mockup all carry. */
.card-plate::before {
    position: absolute;
    inset: 4px;
    border: 1px solid rgb(157 105 55 / 26%);
    border-radius: calc(var(--radius) - 4px);
    pointer-events: none;
    content: '';
}

.card-plate__position {
    font-size: var(--text-2xs);
    font-weight: 620;
    color: var(--color-accent-text);
    text-transform: uppercase;
    letter-spacing: 0.16em;
}

.card-plate__name {
    font-family: var(--font-serif);
    font-size: var(--text-md);
    font-weight: 430;
    line-height: 1.25;
    color: var(--color-text);
}

.card-plate__orientation,
.card-plate__caption {
    font-size: var(--text-xs);
    color: var(--color-muted);
}

/* The glyph: a rune, a hexagram, a numeral or an SVG face. Sized once here so
   every divination method draws its mark at the same weight. */
.card-plate__glyph {
    font-size: 2.25rem;
    line-height: 1.1;
    color: var(--color-gold-light);
}

.card-plate__name--numeral,
.numeral__mono {
    font-variant-numeric: tabular-nums;
}

/* A reversed card is drawn upside down, because that is what "obrácená" means.
   The label under it still reads the right way up. */
.card-plate--reversed .card-plate__glyph,
.card-plate--reversed .tarot-face {
    transform: rotate(180deg);
}

.card-plate--reversed {
    border-color: rgb(192 122 75 / 60%);
}

.card-plate--drawn {
    border-color: var(--color-gold-light);
    box-shadow: var(--plate-shadow), 0 0 26px -10px rgb(224 175 103 / 60%);
}

.card-plate--doubtful {
    border-style: dashed;
}

.card-plate--link {
    transition: border-color var(--transition-fast), transform var(--transition-fast);
}

.card-plate--link:hover {
    border-color: var(--color-gold-light);
    transform: translateY(-2px);
}

.card-plate--link:focus-visible {
    outline: 2px solid var(--color-gold-light);
    outline-offset: 3px;
}

.card-row--index .card-plate {
    padding: var(--space-3) var(--space-2);
}

.card-row--index .card-plate__name {
    font-size: var(--text-base);
}

.card-row__deck {
    font-size: var(--text-xs);
    color: var(--color-muted);
}

/* The SVG face a tarot card draws when there is no illustration for it. */
.tarot-face {
    width: 100%;
    max-width: 6.5rem;
    height: auto;
    color: var(--color-gold-light);
}

.plate-empty {
    color: var(--color-muted);
    font-style: italic;
}

/* =============================================================================
   Reading sections — the body of a finished reading
   ============================================================================= */

.reading-section {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-3);
}

.reading-section__title {
    font-family: var(--font-serif);
    font-size: var(--text-xl);
    font-weight: 430;
    line-height: 1.2;
    color: var(--color-text);
}

.reading-section__body {
    font-size: var(--text-md);
    line-height: 1.85;
    color: var(--color-text-soft);
}

.reading-section__body p + p {
    margin-block-start: var(--space-4);
}

/* The summary is the answer, so it gets the plate and the brass edge; the rest
   of the reading is prose on the page. */
.reading-section--summary {
    padding: var(--space-5);
    background: var(--plate-fill);
    border: 1px solid var(--color-border);
    border-inline-start: 2px solid var(--color-gold);
    border-radius: var(--radius);
    box-shadow: var(--plate-shadow);
}

.reading-section--summary .reading-section__body {
    color: var(--color-text);
}

.reading-list {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-3);
    padding: 0;
    margin: 0;
    list-style: none;
}

.reading-list > li {
    display: grid;
    grid-template-columns: 1.2rem minmax(0, 1fr);
    gap: var(--space-3);
    font-size: var(--text-md);
    line-height: 1.8;
    color: var(--color-text-soft);
}

.reading-list > li::before {
    color: var(--color-gold);
    content: '✦';
}

.reading-list--positive > li::before {
    color: var(--color-success);
    content: '↗';
}

.reading-list--warning > li::before {
    color: var(--color-warning);
    content: '!';
}

/* =============================================================================
   Timeline (Grimoár)
   ============================================================================= */

.timeline {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-6);
}

.timeline__month {
    position: relative;
    font-family: var(--font-serif);
    font-size: var(--text-lg);
    font-weight: 430;
    color: var(--color-accent-text);
}

.timeline__month::after {
    display: block;
    height: 1px;
    margin-block-start: var(--space-2);
    background: var(--rule-gold);
    content: '';
}

.timeline__entries {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-4);
    padding: 0;
    padding-inline-start: var(--space-6);
    margin: 0;
    margin-block-start: var(--space-4);
    list-style: none;
}

/* The spine. Inset so the entry dots sit on it. */
.timeline__entries::before {
    position: absolute;
    inset-block: 6px;
    inset-inline-start: 5px;
    width: 1px;
    background: linear-gradient(180deg, var(--color-border-soft), transparent);
    content: '';
}

.timeline-entry {
    position: relative;
}

.timeline-entry::before {
    position: absolute;
    inset-block-start: 7px;
    inset-inline-start: calc(-1 * var(--space-6) + 1px);
    width: 9px;
    height: 9px;
    background: var(--color-background);
    border: 1px solid var(--color-border);
    border-radius: 50%;
    content: '';
}

.timeline-entry--answered::before {
    background: var(--color-gold);
    border-color: var(--color-gold-light);
}

.timeline-entry__head {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-3);
    align-items: baseline;
}

.timeline-entry__when {
    font-size: var(--text-xs);
    color: var(--color-muted);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.timeline-entry__title {
    font-family: var(--font-serif);
    font-size: var(--text-md);
    font-weight: 430;
    color: var(--color-text);
}

.timeline-entry__body {
    margin-block-start: var(--space-2);
    font-size: var(--text-base);
    line-height: 1.75;
    color: var(--color-muted);
}

/* =============================================================================
   Chat bubbles

   `.chat-bubble` is the canonical name; `.chat-turn` is the same component
   under the name the chat templates use. The wizard speaks from a brass-framed
   plate, the visitor from a plain surface — the asymmetry is the point.
   ============================================================================= */

.chat-thread,
.chat-transcript {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-4);
}

.chat-bubble,
.chat-turn {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-2);
    justify-items: start;
    max-width: min(100%, 46rem);
}

.chat-bubble--user,
.chat-turn--user {
    justify-items: end;
    justify-self: end;
}

.chat-bubble__who,
.chat-turn__who {
    font-size: var(--text-2xs);
    font-weight: 620;
    color: var(--color-muted);
    text-transform: uppercase;
    letter-spacing: 0.16em;
}

.chat-bubble__body,
.chat-turn__body {
    padding: var(--space-4) var(--space-5);
    font-size: var(--text-md);
    line-height: 1.8;
    color: var(--color-text-soft);
    border-radius: var(--radius);
}

.chat-bubble--wizard .chat-bubble__body,
.chat-turn--wizard .chat-turn__body {
    color: var(--color-text);
    background: var(--plate-fill);
    border: 1px solid var(--color-border);
    box-shadow: var(--plate-shadow);
}

.chat-bubble--user .chat-bubble__body,
.chat-turn--user .chat-turn__body {
    background: rgb(28 29 40 / 82%);
    border: 1px solid var(--color-border-neutral);
}

.chat-bubble__body p + p,
.chat-turn__body p + p {
    margin-block-start: var(--space-3);
}

.chat-activity {
    display: inline-flex;
    gap: var(--space-2);
    align-items: center;
    font-size: var(--text-sm);
    color: var(--color-muted);
}

.chat-activity::after {
    animation: chat-dots 1.4s steps(4, end) infinite;
    content: '…';
}

@keyframes chat-dots {
    0% { content: '·'; }
    33% { content: '··'; }
    66% { content: '···'; }
}

.chat-compose {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-3);
}

.chat-compose__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    align-items: center;
    justify-content: space-between;
}

.chat-quota {
    font-size: var(--text-xs);
    color: var(--color-muted);
}

.chat-quota--paid {
    color: var(--color-gold-light);
}

.conversation-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-1);
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--color-border-soft);
    border-radius: var(--radius-sm);
    transition: border-color var(--transition-fast);
}

.conversation-row:hover {
    border-color: var(--color-border);
}

.conversation-row__title {
    font-family: var(--font-serif);
    font-size: var(--text-md);
    color: var(--color-text);
}

.conversation-row:hover .conversation-row__title {
    color: var(--color-gold-light);
}

.conversation-row__when {
    font-size: var(--text-xs);
    color: var(--color-muted);
}

/* =============================================================================
   Upload slots — the vision feature's photo drop zones
   ============================================================================= */

.upload-slots {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
    gap: var(--space-3);
}

.upload-slot {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-2);
    place-items: center;
    min-height: 9rem;
    padding: var(--space-3);
    font-size: var(--text-sm);
    color: var(--color-muted);
    text-align: center;
    cursor: pointer;
    background: var(--plate-fill-soft);
    border: 1px dashed var(--color-border-soft);
    border-radius: var(--radius);
    transition: border-color var(--transition-fast), background var(--transition-fast);
}

.upload-slot:hover,
.upload-slot:focus-within {
    color: var(--color-text-soft);
    border-color: var(--color-gold-light);
}

.upload-slot--filled {
    border-style: solid;
    border-color: var(--color-border);
}

.upload-slot__preview {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    place-items: center;
    width: 100%;
}

.upload-slot__preview img,
.upload-preview img {
    width: 100%;
    max-height: 12rem;
    object-fit: cover;
    border-radius: var(--radius-sm);
}

.upload-slot__label {
    font-size: var(--text-2xs);
    text-transform: uppercase;
    letter-spacing: 0.14em;
}

/* =============================================================================
   Cookie notice
   ============================================================================= */

.cookie-notice {
    position: fixed;
    inset-block-end: 0;
    inset-inline: 0;
    z-index: 60;
    background: rgb(3 8 18 / 97%);
    border-top: 1px solid var(--color-border);
    box-shadow: 0 -18px 50px rgb(0 0 0 / 45%);
}

.cookie-notice__inner {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3) var(--space-5);
    align-items: center;
    justify-content: space-between;
    padding-block: var(--space-3);
}

.cookie-notice__text {
    font-size: var(--text-sm);
    color: var(--color-text-soft);
}

.cookie-notice__button {
    flex: 0 0 auto;
}

/* The bar is fixed, so the page needs room under it or the footer's last line
   sits behind it for the whole first visit. */
body:has(.cookie-notice:not([hidden])) {
    padding-block-end: 5.5rem;
}

/* =============================================================================
   Feature rows — an alternating copy/art band

   The mockup's `.offering` is the homepage's dressed version of this (see
   pages/home.css); `.feature-row` is the undressed one that any subpage can
   use to put a paragraph next to a mark.
   ============================================================================= */

.feature-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-5);
    align-items: center;
    padding-block: var(--space-7);
    border-bottom: 1px solid var(--color-border-soft);
}

.feature-row:last-child {
    border-bottom: 0;
}

.feature-row__art {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    place-items: center;
    order: -1;
}

.feature-row__glyph {
    width: min(100%, 8rem);
    height: auto;
    color: rgb(224 175 103 / 75%);
}

@media (min-width: 52rem) {
    .feature-row {
        grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
        gap: var(--space-8);
    }

    .feature-row__art {
        order: 0;
    }

    .feature-row--mirrored .feature-row__body {
        order: 2;
    }
}

/* =============================================================================
   Sample — a specimen block, plainly labelled as invented
   ============================================================================= */

.sample {
    position: relative;
    padding: var(--space-6) var(--space-5) var(--space-5);
    background: var(--plate-fill);
    border: 1px solid var(--color-border-soft);
    border-radius: var(--radius);
}

.sample__mark {
    position: absolute;
    inset-block-start: 0;
    inset-inline-start: var(--space-5);
    padding: 3px 10px;
    font-size: var(--text-2xs);
    font-weight: 620;
    color: var(--color-text-inverse);
    text-transform: uppercase;
    letter-spacing: 0.16em;
    background: var(--color-gold-light);
    border-radius: 0 0 var(--radius-sm) var(--radius-sm);
    transform: translateY(-1px);
}

.sample__question {
    font-family: var(--font-serif);
    font-size: var(--text-lg);
    font-style: italic;
    line-height: 1.5;
    color: var(--color-gold-light);
}

/* =============================================================================
   Auth pages
   ============================================================================= */

.auth {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-5);
    width: min(100% - 2 * var(--space-5), 26rem);
    margin-inline: auto;
    padding-block: var(--space-8);
}

.auth__plate {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-4);
    padding: var(--space-6) var(--space-5);
    background: var(--plate-fill);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--plate-shadow);
}

.auth__submit {
    width: 100%;
}

.auth__footnote,
.auth__link {
    font-size: var(--text-sm);
    color: var(--color-muted);
    text-align: center;
}

/* =============================================================================
   Account, balance, credits
   ============================================================================= */

.account-fact {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-1);
    font-size: var(--text-base);
    color: var(--color-text-soft);
}

.account-code,
.voucher-code,
.code {
    display: inline-block;
    padding: 2px 8px;
    font-family: var(--font-mono);
    font-size: var(--text-sm);
    color: var(--color-gold-light);
    letter-spacing: 0.08em;
    background: rgb(3 8 18 / 80%);
    border: 1px solid var(--color-border-soft);
    border-radius: var(--radius-sm);
}

.account-invite-link {
    overflow-wrap: anywhere;
}

.balance {
    display: flex;
    gap: var(--space-2);
    align-items: baseline;
}

.balance__amount {
    font-family: var(--font-serif);
    font-size: var(--text-3xl);
    font-weight: 390;
    line-height: 1;
    color: var(--color-gold-light);
    font-variant-numeric: tabular-nums;
}

.balance__unit {
    font-size: var(--text-sm);
    color: var(--color-muted);
    text-transform: uppercase;
    letter-spacing: 0.14em;
}

.export-list {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-2);
    padding: 0;
    margin: 0;
    list-style: none;
}

.export-list > li {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    align-items: center;
    justify-content: space-between;
    padding: var(--space-2) var(--space-3);
    font-size: var(--text-sm);
    border: 1px solid var(--color-border-soft);
    border-radius: var(--radius-sm);
}

/* =============================================================================
   Paywall

   `.paywall-fade` used to live here: a clipped box that faded the last free
   paragraph out. Phase 2 replaced it with `.seam` — a preview has to look like
   a reading that was *stopped*, not one that trails off — and the one template
   that carried it carried `.rd-seam` beside it, so every declaration in it was
   already being cancelled. Deleted, together with the cancellations.
   ============================================================================= */

.paywall {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-3);
    justify-items: center;
    padding: var(--space-6) var(--space-5);
    text-align: center;
    background: var(--plate-fill);
    border: 1px solid var(--color-gold-light);
    border-radius: var(--radius);
    box-shadow: var(--plate-shadow), 0 0 40px -18px rgb(224 175 103 / 60%);
}

.paywall__lock {
    font-size: 1.6rem;
    color: var(--color-gold-light);
}

.paywall__title {
    font-family: var(--font-serif);
    font-size: var(--text-xl);
    font-weight: 430;
}

.paywall__price {
    font-family: var(--font-serif);
    font-size: var(--text-2xl);
    color: var(--color-gold-light);
}

.paywall__note {
    font-size: var(--text-sm);
    color: var(--color-muted);
}

.paywall__contents {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-1);
    padding: 0;
    margin: 0;
    font-size: var(--text-base);
    color: var(--color-text-soft);
    list-style: none;
}

.paywall__contents > li::before {
    margin-inline-end: var(--space-2);
    color: var(--color-gold);
    content: '✦';
}

/* =============================================================================
   Reading list rows, waiting screen, follow-ups
   ============================================================================= */

.reading-row__head {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-3);
    align-items: baseline;
    justify-content: space-between;
}

.reading-row__teaser {
    font-size: var(--text-base);
    line-height: 1.7;
    color: var(--color-muted);
}

.reading-followups {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-2);
}

.reading-wait {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-4);
    place-items: center;
    padding-block: var(--space-8);
    text-align: center;
}

.reading-wait__title {
    font-family: var(--font-serif);
    font-size: var(--text-2xl);
    font-weight: 390;
}

.reading-wait__sigil {
    color: var(--color-gold);
    animation: reading-pulse 2.6s ease-in-out infinite;
}

@keyframes reading-pulse {
    0%, 100% { opacity: 0.45; }
    50% { opacity: 1; }
}

/* =============================================================================
   Grimoire — memory, themes
   ============================================================================= */

.memory + .memory {
    margin-block-start: var(--space-3);
}

.memory__text {
    font-size: var(--text-md);
    line-height: 1.8;
    color: var(--color-text-soft);
}

.theme-list {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-3);
}

.theme-row {
    display: grid;
    grid-template-columns: minmax(6rem, 10rem) minmax(0, 1fr) 3rem;
    gap: var(--space-3);
    align-items: center;
    font-size: var(--text-base);
}

.theme-row__name {
    color: var(--color-text-soft);
}

.theme-row__bar {
    /* `display: block` because the markup uses a <span>: an inline box ignores
       height, and the track would be a hairline. */
    display: block;
    height: 6px;
    overflow: hidden;
    background: rgb(157 105 55 / 18%);
    border-radius: var(--radius-pill);
}

.theme-row__fill {
    display: block;
    height: 100%;
    background: linear-gradient(90deg, var(--color-gold), var(--color-gold-light));
    border-radius: inherit;
}

.theme-row__count {
    color: var(--color-muted);
    text-align: end;
    font-variant-numeric: tabular-nums;
}

/* =============================================================================
   Numerology
   ============================================================================= */

.numeral-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
    gap: var(--space-4);
}

.numeral {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-2);
    padding: var(--space-5);
    background: var(--plate-fill);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--plate-shadow);
}

.numeral__value {
    font-family: var(--font-serif);
    font-size: 2.75rem;
    font-weight: 300;
    line-height: 1;
    color: var(--color-gold-light);
    font-variant-numeric: tabular-nums;
}

.numeral__heading {
    font-family: var(--font-serif);
    font-size: var(--text-lg);
    font-weight: 430;
}

.numeral__note {
    font-size: var(--text-base);
    line-height: 1.75;
    color: var(--color-muted);
}

.numeral__steps {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-1);
    padding: 0;
    margin: 0;
    list-style: none;
}

.numeral__step {
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    color: var(--color-muted);
}

.match-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-1);
    padding-block: var(--space-3);
    border-bottom: 1px solid rgb(153 105 59 / 16%);
}

.match-row:last-child {
    border-bottom: 0;
}

.match-row__who {
    font-family: var(--font-serif);
    font-size: var(--text-md);
    color: var(--color-text);
}

.match-row__note {
    font-size: var(--text-base);
    color: var(--color-muted);
}

/* =============================================================================
   Astrology — the chart wheel, place picker
   ============================================================================= */

.chart-wheel {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    place-items: center;
}

.chart-wheel svg {
    width: min(100%, 32rem);
    height: auto;
    color: var(--color-gold-light);
}

.wheel-caption {
    font-size: var(--text-sm);
    color: var(--color-muted);
    text-align: center;
}

.place-results {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-1);
    margin-block-start: var(--space-2);
}

.place-option {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 2px;
    padding: var(--space-2) var(--space-3);
    font-size: var(--text-base);
    text-align: start;
    cursor: pointer;
    background: var(--plate-fill-soft);
    border: 1px solid var(--color-border-soft);
    border-radius: var(--radius-sm);
    transition: border-color var(--transition-fast);
}

.place-option:hover,
.place-option:focus-visible {
    border-color: var(--color-gold-light);
}

/* =============================================================================
   Product motif, sigil, triad — the decorative marks
   ============================================================================= */

.product-motif,
.sigil {
    color: var(--color-gold);
}

.product-motif svg {
    width: min(100%, 10rem);
    height: auto;
}

.triad {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: var(--space-4);
}

.triad__item {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-2);
    justify-items: center;
    padding: var(--space-5);
    text-align: center;
    background: var(--plate-fill-soft);
    border: 1px solid var(--color-border-soft);
    border-radius: var(--radius);
    transition: border-color var(--transition-fast);
}

.triad__item:hover {
    border-color: var(--color-border);
}

.triad__glyph {
    width: 3rem;
    height: 3rem;
    color: var(--color-gold-light);
    transition: transform var(--transition);
}

.triad__item:hover .triad__glyph {
    transform: scale(1.06);
}

.triad__name {
    font-family: var(--font-serif);
    font-size: var(--text-lg);
    font-weight: 430;
}

.triad__note {
    font-size: var(--text-base);
    color: var(--color-muted);
}

/* =============================================================================
   Persona picker
   ============================================================================= */

.persona-choices {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
    gap: var(--space-3);
}

.persona-choice {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: var(--space-3);
    align-items: start;
    padding: var(--space-4);
    cursor: pointer;
    background: var(--plate-fill-soft);
    border: 1px solid var(--color-border-soft);
    border-radius: var(--radius);
    transition: border-color var(--transition-fast), background var(--transition-fast);
}

.persona-choice:focus-within {
    outline: 2px solid var(--color-gold-light);
    outline-offset: 2px;
}

.persona-choice--on {
    background: rgb(200 145 76 / 10%);
    border-color: var(--color-gold-light);
}

.persona-choice input {
    margin-block-start: 4px;
}

.persona-choice__mark,
.persona-mark {
    color: var(--color-gold-light);
}

.persona-choice__name {
    font-family: var(--font-serif);
    font-size: var(--text-md);
    font-weight: 430;
}

.persona-choice__note {
    font-size: var(--text-sm);
    line-height: 1.65;
    color: var(--color-muted);
}

/* =============================================================================
   Voice — dictation button and the hands-free bar
   ============================================================================= */

.chat-voice:not([hidden]),
.voice-mode:not([hidden]) {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-2);
}

.chat-voice__button,
.voice-mode__button {
    display: inline-flex;
    gap: var(--space-2);
    align-items: center;
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
    padding-inline: var(--space-3);
    color: var(--color-muted);
    cursor: pointer;
    background: var(--plate-fill-soft);
    border: 1px solid var(--color-border-soft);
    border-radius: var(--radius-control);
    transition: color var(--transition-fast), border-color var(--transition-fast);
}

.chat-voice__button:hover,
.voice-mode__button:hover {
    color: var(--color-gold-light);
    border-color: var(--color-border);
}

.chat-voice__button--active,
.voice-mode__button--active {
    color: var(--color-gold-bright);
    border-color: var(--color-gold-light);
    background: rgb(200 145 76 / 14%);
}

.chat-voice__icon,
.voice-mode__icon {
    width: 1.15rem;
    height: 1.15rem;
}

.chat-voice__note,
.voice-mode__note,
.voice-mode__status,
.voice-mode__heard {
    font-size: var(--text-sm);
    color: var(--color-muted);
}

.voice-mode--speaking .voice-mode__status {
    color: var(--color-gold-light);
}

.voice-mode--error .voice-mode__status {
    color: var(--color-danger);
}

.voice-mode__bar {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    align-items: center;
    padding: var(--space-3) var(--space-4);
    background: var(--plate-fill-soft);
    border: 1px solid var(--color-border-soft);
    border-radius: var(--radius);
}

.voice-mode__wave:not([hidden]) {
    display: inline-flex;
    gap: 3px;
    align-items: center;
    height: 1.2rem;
}

.voice-mode__wave > span {
    width: 3px;
    height: 40%;
    background: var(--color-gold);
    border-radius: var(--radius-pill);
}

.voice-mode--listening .voice-mode__wave > span,
.voice-mode--speaking .voice-mode__wave > span {
    animation: voice-wave 900ms ease-in-out infinite;
}

.voice-mode--listening .voice-mode__wave > span:nth-child(2),
.voice-mode--speaking .voice-mode__wave > span:nth-child(2) {
    animation-delay: 140ms;
}

.voice-mode--listening .voice-mode__wave > span:nth-child(3),
.voice-mode--speaking .voice-mode__wave > span:nth-child(3) {
    animation-delay: 280ms;
}

@keyframes voice-wave {
    0%, 100% { height: 30%; }
    50% { height: 100%; }
}

.chat-turn__play {
    color: var(--color-muted);
}

/* =============================================================================
   Knowledge base — entry heads, hexagram lines, runes, dream journal
   ============================================================================= */

.entry-head {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-4);
    align-items: center;
}

@media (min-width: 40rem) {
    .entry-head {
        grid-template-columns: 11rem minmax(0, 1fr);
    }
}

.entry-head__plate {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-2);
    place-items: center;
    padding: var(--space-4);
    text-align: center;
    background: var(--plate-fill);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--plate-shadow);
}

.entry-facts {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-3);
    padding: 0;
    margin: 0;
    font-size: var(--text-sm);
    color: var(--color-muted);
    list-style: none;
}

.entry-facts__item + .entry-facts__item::before {
    margin-inline-end: var(--space-3);
    color: rgb(184 128 66 / 55%);
    content: '·';
}

.hexagram-lines {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-2);
    padding: 0;
    margin: 0;
    list-style: none;
}

.hexagram-lines__item {
    display: grid;
    grid-template-columns: 2rem minmax(0, 1fr);
    gap: var(--space-3);
    font-size: var(--text-base);
    line-height: 1.7;
    color: var(--color-text-soft);
}

.hexagram-lines__number {
    font-family: var(--font-serif);
    color: var(--color-gold-light);
    text-align: end;
}

/* Runic staves. No local font on this machine covers U+16A0–16F8; the family is
   loaded from Google Fonts in base.html.twig, which is why the CSP still names
   fonts.googleapis.com / fonts.gstatic.com. The fallbacks after it are the
   system faces that do have the block, in the order they are likely to exist. */
.face,
.card-plate__glyph--rune {
    font-family: 'Noto Sans Runic', 'Segoe UI Historic', 'Segoe UI Symbol', 'Apple Symbols', 'Noto Sans Symbols 2', serif;
}

.dream-text {
    font-size: var(--text-md);
    line-height: 1.9;
    color: var(--color-text-soft);
    white-space: pre-wrap;
}

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

.journal-search__input {
    flex: 1 1 14rem;
}

/* =============================================================================
   Vision plates
   ============================================================================= */

.vision-plates {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: var(--space-3);
}

.vision-plate {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-2);
    padding: var(--space-4);
    background: var(--plate-fill-soft);
    border: 1px solid var(--color-border-soft);
    border-radius: var(--radius);
}

.vision-plate--uncertain {
    border-style: dashed;
}

.vision-plate__title {
    font-family: var(--font-serif);
    font-size: var(--text-md);
    font-weight: 430;
}

.vision-plate__where,
.vision-plate__confidence {
    font-size: var(--text-xs);
    color: var(--color-muted);
}

.vision-plate__list {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-1);
    padding: 0;
    margin: 0;
    font-size: var(--text-base);
    color: var(--color-text-soft);
    list-style: none;
}

/* =============================================================================
   Legal pages
   ============================================================================= */

.legal {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-6);
}

.legal__meta {
    font-size: var(--text-sm);
    color: var(--color-muted);
}

.legal__section > * + * {
    margin-block-start: var(--space-4);
}

.legal__section h2 {
    font-size: var(--text-xl);
    color: var(--color-gold-light);
}

.legal__section h3 {
    font-size: var(--text-lg);
}

.legal__section ul {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-2);
    padding-inline-start: var(--space-5);
}

.legal__section li {
    font-size: var(--text-base);
    line-height: 1.8;
    color: var(--color-text-soft);
}

.legal__section p {
    font-size: var(--text-base);
    line-height: 1.85;
    color: var(--color-text-soft);
}

.legal__party > * + * {
    margin-block-start: var(--space-2);
}

.legal__table {
    width: 100%;
    font-size: var(--text-base);
    border-collapse: collapse;
}

.legal__table th,
.legal__table td {
    padding: var(--space-2) var(--space-3);
    text-align: start;
    vertical-align: top;
    border-bottom: 1px solid rgb(153 105 59 / 16%);
}

.legal__table th {
    font-size: var(--text-xs);
    color: var(--color-accent-text);
    text-transform: uppercase;
    letter-spacing: 0.12em;
}

.legal__table tbody tr:last-child td {
    border-bottom: 0;
}

.legal__table code {
    color: var(--color-gold-light);
}

.legal__section--disclaimer,
.legal__section--highlight {
    padding: var(--space-5);
    background: rgb(200 145 76 / 8%);
    border: 1px solid var(--color-border-soft);
    border-radius: var(--radius);
}

.legal__disclaimer {
    font-size: var(--text-base);
    line-height: 1.85;
    color: var(--color-text);
}

/* A placeholder somebody still owes a lawyer. Loud on purpose — it is meant to
   be impossible to ship by accident. */
.todo-legal,
mark.todo-legal {
    padding: 0 4px;
    color: var(--color-text-inverse);
    background: var(--color-warning);
    border-radius: 2px;
}

.digital-consent {
    font-size: var(--text-sm);
    line-height: 1.7;
    color: var(--color-muted);
}

/* =============================================================================
   Odds and ends still on real pages
   ============================================================================= */

.prose > * + * {
    margin-block-start: var(--space-4);
}

.prose p,
.prose li {
    font-size: var(--text-md);
    line-height: 1.85;
    color: var(--color-text-soft);
}

.prose h2 {
    margin-block-start: var(--space-6);
}

.daily-card {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-5);
    align-items: center;
}

@media (min-width: 40rem) {
    .daily-card {
        grid-template-columns: 14rem minmax(0, 1fr);
    }
}

.daily-card__plate {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-2);
    place-items: center;
    padding: var(--space-5);
    text-align: center;
    background: var(--plate-fill);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--plate-shadow);
}

.daily-card__body {
    font-size: var(--text-md);
    line-height: 1.85;
    color: var(--color-text-soft);
}

.lead-capture__form,
.gift-form {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-3);
}

.voucher-message {
    font-size: var(--text-base);
    color: var(--color-muted);
}

.recommendations {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-3);
}

.recommendation {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-2);
    padding: var(--space-4);
    background: var(--plate-fill-soft);
    border: 1px solid var(--color-border-soft);
    border-radius: var(--radius);
}

.recommendation__title {
    font-family: var(--font-serif);
    font-size: var(--text-md);
    font-weight: 430;
}

.recommendation__body {
    font-size: var(--text-base);
    line-height: 1.75;
    color: var(--color-muted);
}

.recommendation__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.entry-facts__item,
.points {
    font-size: var(--text-base);
}

.point-mark {
    color: var(--color-gold);
}

.point-text {
    color: var(--color-text-soft);
}

/* =============================================================================
   Promoted from the page files — phase 2 consolidation

   Thirteen objects that three different areas had each invented under their own
   prefix. Each one is declared once here under a name that says what it is, with
   the prefixed name it was born with listed alongside so no template had to be
   edited: `.rd-seam, .seam { … }` is one rule, not two.

   The section sits at the foot of the file on purpose. A promoted rule has to
   keep winning over the component it modifies — `.page-head`, `.card`,
   `.section-header` — and a page file that loads after this one can still
   override any of it.

   old (page file)              canonical (here)
   ---------------------------  ----------------------------------------------
   .rd-head, .rd-head__meta     .page-head--ruled, .page-head__meta
   .rd-seam                     .seam
   .rd-question                 .question-door
   .rd-row__stamp/__day/__month .date-stamp/__day/__month
   .rd-memory                   .memory-quote
   .acct-split                  .split
   .acct-tile                   .tile
   .acct-status                 .status-pair
   .acct-panel--empty           .panel--empty
   .acct-empty__title           .empty-state__title   (merged, see above)
   .kn-head*                    .masthead*
   .kn-rail*                    .chip-rail*
   .kn-group__head/__count/__rule  .group-head/__count/__rule
   .kn-hero*                    .entry-hero*
   .kn-empty                    .empty-state          (aliased, see above)
   ============================================================================= */

/* --- A ruled page head ----------------------------------------------------- */

/* `.section-header` / `.page-head` with three things added: a brass rule in
   front of the eyebrow, a meta line that holds badges rather than sentences,
   and a hairline underneath that closes the head off from the document below.
   A modifier — the element keeps `.section-header` or `.page-head`, which is
   what makes it a grid. */
.rd-head,
.page-head--ruled {
    gap: var(--space-2);
    padding-block-end: var(--space-5);
}

.rd-head > .overline,
.page-head--ruled > .overline {
    display: flex;
    gap: 11px;
    align-items: center;
}

.rd-head > .overline::before,
.page-head--ruled > .overline::before {
    flex: none;
    width: 31px;
    height: 1px;
    background: var(--color-gold);
    content: '';
}

.rd-head .section-header__title,
.page-head--ruled :is(.section-header__title, .page-head__title) {
    font-size: var(--text-3xl);
    letter-spacing: -0.02em;
}

/* Badges sit on their own line and never inherit the lede's line-height, which
   would leave them floating half a line above their own row. */
.rd-head__meta,
.page-head__meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    align-items: center;
    margin-block-start: var(--space-1);
    line-height: 1;
}

.rd-head::after,
.page-head--ruled::after {
    height: 1px;
    background: var(--rule-gold-fade);
    content: '';
}

.rd-head--centered,
.page-head--ruled.page-head--centered {
    justify-items: center;
    text-align: center;
}

.rd-head--centered > .overline,
.page-head--ruled.page-head--centered > .overline {
    justify-content: center;
}

.rd-head--centered > .overline::before,
.page-head--ruled.page-head--centered > .overline::before {
    display: none;
}

.rd-head--centered::after,
.page-head--ruled.page-head--centered::after {
    background: var(--rule-gold);
}

/* --- The seam ------------------------------------------------------------- */

/* A brass tear-line with a mark on it: "the content stops here". The paywall
   drew it first; a dream journal cut off at the free entries wants the same
   object. Nothing is blurred and no ghost paragraphs are drawn, because both
   would be a picture of writing we are not showing.

   It replaced `.paywall-fade`, which was a masked, clipped box: the mask would
   have eaten the tear-line and the clip would have cut the mark off it. */
.rd-seam,
.seam {
    position: relative;
    height: 3.5rem;
    background: radial-gradient(ellipse at 50% 100%, rgb(200 145 76 / 10%), transparent 70%);
}

.rd-seam::before,
.seam::before {
    position: absolute;
    inset-block-end: 0;
    inset-inline: 0;
    height: 1px;
    background:
        repeating-linear-gradient(90deg, rgb(180 123 60 / 60%) 0 7px, transparent 7px 14px);
    mask-image: linear-gradient(90deg, transparent, #000 18%, #000 82%, transparent);
    content: '';
}

.rd-seam::after,
.seam::after {
    position: absolute;
    inset-block-end: -8px;
    inset-inline-start: 50%;
    width: 18px;
    height: 17px;
    font-size: 13px;
    line-height: 17px;
    color: var(--color-gold);
    text-align: center;
    background: var(--color-background);
    transform: translateX(-50%);
    content: '✦';
}

/* --- The question door ----------------------------------------------------- */

/* A link that is a whole sentence, on a plate: a mark, the question, and an
   arrow that leans forward on hover. */
.rd-question,
.question-door {
    display: grid;
    grid-template-columns: 1.1rem minmax(0, 1fr) 1.2rem;
    gap: var(--space-3);
    align-items: center;
    padding: var(--space-4);
    background: var(--plate-fill-soft);
    border: 1px solid var(--color-border-soft);
    border-radius: var(--radius);
    transition:
        border-color var(--transition-fast),
        background var(--transition-fast),
        transform var(--transition-fast);
}

.rd-question:hover,
.question-door:hover {
    background: var(--plate-fill);
    border-color: var(--color-gold-light);
    transform: translateY(-2px);
}

.rd-question__mark,
.rd-question__go,
.question-door__mark,
.question-door__go {
    font-size: var(--text-lg);
    line-height: 1;
    color: var(--color-gold);
    transition: color var(--transition-fast), transform var(--transition-fast);
}

.rd-question__text,
.question-door__text {
    font-family: var(--font-serif);
    font-size: var(--text-md);
    font-weight: 430;
    line-height: 1.4;
    color: var(--color-text);
}

.rd-question:hover .rd-question__mark,
.rd-question:hover .rd-question__go,
.question-door:hover :is(.question-door__mark, .question-door__go) {
    color: var(--color-gold-bright);
}

.rd-question__go,
.question-door__go {
    justify-self: end;
}

.rd-question:hover .rd-question__go,
.question-door:hover .question-door__go {
    transform: translateX(3px);
}

/* --- The date stamp -------------------------------------------------------- */

/* A date in the margin, set in the display serif and in tabular figures so a
   column of them lines up. The reading list, the dream journal and the
   notification list are the same object. */
.rd-row__stamp,
.date-stamp {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 2px;
    justify-items: center;
    align-content: start;
    padding-block-end: var(--space-2);
    text-align: center;
    border-block-end: 1px solid var(--color-border-soft);
}

.rd-row__day,
.date-stamp__day {
    font-family: var(--font-serif);
    font-size: var(--text-2xl);
    font-weight: 390;
    line-height: 1;
    color: var(--color-gold-light);
    font-variant-numeric: tabular-nums;
}

.rd-row__month,
.date-stamp__month {
    font-size: var(--text-2xs);
    color: var(--color-muted);
    text-transform: uppercase;
    letter-spacing: 0.12em;
}

/* On a phone the margin is gone, so the stamp lies down and reads as one line
   above the row rather than as a column beside it. */
@media (max-width: 479px) {
    .rd-row__stamp,
    .date-stamp {
        grid-auto-flow: column;
        gap: var(--space-2);
        justify-content: start;
        justify-items: start;
        align-items: baseline;
        border-block-end: 0;
        padding-block-end: 0;
    }

    .rd-row__day,
    .date-stamp__day {
        font-size: var(--text-lg);
    }
}

/* --- The memory quote ------------------------------------------------------ */

/* Three things in two rows: the provenance badges on the left of the first row,
   the control at the right of it, and the quoted sentence across the second.
   The button belongs on the badge row rather than under the quotation — a row
   of full-width buttons down the page turns a list of sentences into a list of
   controls. */
.rd-memory,
.memory-quote {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: var(--space-3);
    align-items: start;
    padding: var(--space-4) var(--space-5);
    background: var(--plate-fill-soft);
    border: 1px solid var(--color-border-soft);
    border-radius: var(--radius);
}

.rd-memory__meta,
.memory-quote__meta {
    grid-column: 1;
    grid-row: 1;
    gap: var(--space-2);
    justify-content: flex-start;
}

.rd-memory > form,
.memory-quote > form {
    grid-column: 2;
    grid-row: 1;
    justify-self: end;
}

/* The Czech opening quote sits *on* the baseline, so it inherits the
   paragraph's line-height rather than being given one: that is what puts it on
   the first line rather than a third of a line under it. */
.rd-memory .memory__text,
.memory-quote .memory__text {
    position: relative;
    grid-column: 1 / -1;
    grid-row: 2;
    padding-inline-start: var(--space-5);
    color: var(--color-text);
}

.rd-memory .memory__text::before,
.memory-quote .memory__text::before {
    position: absolute;
    inset-block-start: 0;
    inset-inline-start: 0;
    font-family: var(--font-serif);
    font-size: 1.6rem;
    line-height: inherit;
    color: rgb(200 145 76 / 60%);
    content: '„';
}

@media (max-width: 559px) {
    .rd-memory,
    .memory-quote {
        grid-template-columns: minmax(0, 1fr);
    }

    .rd-memory > form,
    .memory-quote > form {
        grid-column: 1;
        grid-row: 3;
        justify-self: start;
    }
}

/* --- The split ------------------------------------------------------------- */

/* A thing and its companion: a form and the notes beside it, the last reading
   and the purse. Two columns above 62rem, one below. */
.acct-split,
.split {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-5);
}

@media (width >= 62rem) {
    .acct-split,
    .split {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    }

    /* A form is the task; the notes beside it are context, and context gets
       less room. */
    .acct-split--form,
    .split--form {
        grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
    }
}

/* --- The tile -------------------------------------------------------------- */

/* A `.card` with a mark, a name and a sentence, where the whole plate is the
   link: the anchor covers it with a stretched pseudo-element, so the click
   target is the plate while the accessible name stays the words. */
.acct-tile,
.tile {
    position: relative;
    gap: var(--space-3);
    padding: var(--space-5);
    transition: border-color var(--transition-fast), transform var(--transition-fast);
}

.acct-tile:hover,
.acct-tile:focus-within,
.tile:hover,
.tile:focus-within {
    border-color: var(--color-gold-light);
    transform: translateY(-2px);
}

.acct-tile__glyph,
.tile__glyph {
    display: block;
    width: 44px;
    color: var(--color-gold-light);
    opacity: 0.9;
}

.acct-tile__glyph svg,
.tile__glyph svg {
    width: 100%;
    height: auto;
}

.acct-tile__name,
.tile__name {
    font-family: var(--font-serif);
    font-size: var(--text-lg);
    font-weight: 430;
    line-height: 1.25;
    letter-spacing: 0;
}

.acct-tile__link,
.tile__link {
    color: var(--color-text);
    transition: color var(--transition-fast);
}

.acct-tile:hover .acct-tile__link,
.tile:hover .tile__link {
    color: var(--color-gold-bright);
}

.acct-tile__link::after,
.tile__link::after {
    position: absolute;
    inset: 0;
    border-radius: var(--radius);
    content: '';
}

/* The ring belongs on the plate, not on the invisible overlay. */
.acct-tile__link:focus-visible,
.tile__link:focus-visible {
    outline: none;
}

.acct-tile:has(.acct-tile__link:focus-visible),
.tile:has(.tile__link:focus-visible) {
    outline: 2px solid var(--color-gold-light);
    outline-offset: 3px;
}

.acct-tile__note,
.tile__note {
    font-size: var(--text-sm);
    line-height: 1.7;
    color: var(--color-muted);
}

.acct-tile--stat .balance,
.tile--stat .balance {
    margin-block-start: var(--space-1);
}

.acct-tile--stat .balance__amount,
.tile--stat .balance__amount {
    font-size: var(--text-2xl);
}

/* --- The status pair ------------------------------------------------------- */

/* "Here is a fact about your account, here is the one button that changes it",
   twice, on one plate, with a hairline between them. */
.acct-status,
.status-pair {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-5);
}

@media (width >= 48rem) {
    .acct-status,
    .status-pair {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: var(--space-6);
    }

    /* The hairline between the two halves, drawn on the second so it never
       appears when only one is present. */
    .acct-status > .acct-status__item + .acct-status__item,
    .status-pair > .status-pair__item + .status-pair__item {
        padding-inline-start: var(--space-6);
        border-inline-start: 1px solid var(--color-border-soft);
    }
}

.acct-status__item,
.status-pair__item {
    gap: var(--space-2);
}

/* A badge and the sentence it belongs to, on one line that wraps as a unit. */
.acct-status__line,
.status-pair__line {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    align-items: baseline;
    font-size: var(--text-base);
    color: var(--color-text-soft);
}

.acct-status__item .btn,
.acct-status__item form,
.status-pair__item .btn,
.status-pair__item form {
    margin-block-start: var(--space-2);
}

/* --- The empty panel ------------------------------------------------------- */

/* An empty state and an invitation are the same plate with different weight:
   the mark, one Fraunces line, one muted paragraph, one button. A modifier on
   `.card`, and written as `.card.panel--empty` because the page-level plate
   classes that load after this file set a gap and a padding of their own. */
.card.acct-panel--empty,
.card.acct-panel--invite,
.card.panel--empty,
.card.panel--invite {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-3);
    padding-block: var(--space-7);
    text-align: center;
    justify-items: center;
}

.card.acct-panel--empty,
.card.panel--empty {
    background: var(--plate-fill-soft);
    border-style: dashed;
    border-color: var(--color-border-soft);
}

/* The mark on it is a tile's mark at invitation size and in quieter brass. */
:is(.acct-panel--empty, .acct-panel--invite, .panel--empty, .panel--invite)
    :is(.acct-tile__glyph, .tile__glyph) {
    width: 52px;
    color: var(--color-gold);
    opacity: 0.75;
}

:is(.acct-panel--empty, .acct-panel--invite, .panel--empty, .panel--invite)
    .field__help {
    max-width: 58ch;
}

/* `:where(.card, …) > .btn` above pins a button to the start of its plate,
   which is right everywhere except on the plates whose whole content is
   centred. Written with `.card` again so it outranks a page file's own plate. */
.card.acct-panel--empty > .btn,
.card.acct-panel--invite > .btn,
.card.panel--empty > .btn,
.card.panel--invite > .btn {
    justify-self: center;
}

/* --- The masthead ---------------------------------------------------------- */

/* The band an index page opens with: a plane of `--color-band` with a soft glow
   at the top, a hairline on both edges, and a mark flanked by two short rules
   so it reads as an engraved device and not as an icon. A detail page does not
   get one, because a document opens with its title.

   `--kn-accent` is the knowledge base's per-tradition accent; anywhere else the
   band falls back to brass. */
.kn-head,
.masthead {
    position: relative;
    padding-block: var(--space-7) var(--space-8);
    overflow: hidden;
    text-align: center;
    background:
        radial-gradient(ellipse at 50% 0%, rgb(25 22 45 / 30%), transparent 60%),
        var(--color-band);
    border-block: 1px solid var(--color-border-soft);
}

.kn-head::after,
.masthead::after {
    position: absolute;
    inset-inline: 0;
    inset-block-end: 0;
    height: 1px;
    background: var(--rule-gold);
    content: '';
}

.kn-head__inner,
.masthead__inner {
    position: relative;
    z-index: 1;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-3);
    justify-items: center;
}

.kn-head__mark,
.masthead__mark {
    display: flex;
    gap: var(--space-4);
    align-items: center;
    justify-content: center;
    width: 100%;
    color: var(--kn-accent, var(--color-gold));
}

.kn-head__mark::before,
.kn-head__mark::after,
.masthead__mark::before,
.masthead__mark::after {
    width: min(24vw, 7.5rem);
    height: 1px;
    background: var(--rule-gold-fade);
    content: '';
}

.kn-head__mark::after,
.masthead__mark::after {
    transform: scaleX(-1);
}

.kn-head .overline,
.masthead .overline {
    color: var(--kn-accent, var(--color-gold));
}

.kn-head__title,
.masthead__title {
    margin-block-start: var(--space-1);
}

.kn-head__lede,
.masthead__lede {
    max-width: 60ch;
    margin-inline: auto;
    font-size: var(--text-md);
    line-height: 1.8;
    color: var(--color-text-soft);
}

/* „78 karet · pět skupin" — the one line that tells a reader how big the thing
   in front of them is before they start scrolling it. */
.kn-head__meta,
.masthead__meta {
    font-size: var(--text-xs);
    color: var(--color-muted);
    text-transform: uppercase;
    letter-spacing: 0.16em;
}

@media (max-width: 40rem) {
    .kn-head,
    .masthead {
        padding-block: var(--space-6) var(--space-7);
    }

    .kn-head__mark::before,
    .kn-head__mark::after,
    .masthead__mark::before,
    .masthead__mark::after {
        width: min(18vw, 4rem);
    }
}

/* --- The chip rail --------------------------------------------------------- */

/* Jump chips over a long index. Sticky, because the point of a jump rail is to
   still be there after you have jumped once. On a narrow screen it scrolls
   inside its own box rather than letting the page scroll sideways (rule 2).

   The negative inline margin puts the rail's ground under the container's own
   gutters, so plates scrolling past it disappear under the whole strip and not
   under the middle of it. It cancels exactly against the padding, so the row
   still lines up with the grid below and the page still cannot scroll sideways
   — `.container` is `100% - 2 × space-5` wide and this makes it 100%. */
.kn-rail,
.chip-rail {
    position: sticky;
    z-index: 3;
    inset-block-start: 0;
    padding-block: var(--space-3);
    padding-inline: var(--space-5);
    margin-block-end: var(--space-6);
    margin-inline: calc(-1 * var(--space-5));
    background: linear-gradient(var(--color-background) 72%, rgb(5 11 21 / 0%));
}

.kn-rail__inner,
.chip-rail__inner {
    display: flex;
    gap: var(--space-2);
    align-items: center;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: thin;
}

.kn-rail .filter-chip,
.chip-rail .filter-chip {
    flex: none;
}

.kn-rail__label,
.chip-rail__label {
    flex: none;
    padding-inline-end: var(--space-1);
    font-size: var(--text-2xs);
    color: var(--color-muted);
    text-transform: uppercase;
    letter-spacing: 0.16em;
}

/* --- The group head -------------------------------------------------------- */

/* „Velká arkána · 22 karet" — a heading, a count, and a rule that fills
   whatever is left of the row and stops at the edge of the grid below it,
   which is what makes the two read as one block. */
.kn-group__head,
.group-head {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    align-items: baseline;
    margin-block-end: var(--space-4);
}

.kn-group__count,
.group-head__count {
    font-size: var(--text-xs);
    color: var(--color-muted);
    text-transform: uppercase;
    white-space: nowrap;
    letter-spacing: 0.16em;
}

.kn-group__rule,
.group-head__rule {
    flex: 1 1 3rem;
    min-width: 2rem;
    height: 1px;
    background: linear-gradient(90deg, var(--kn-accent, var(--color-gold)), rgb(157 105 55 / 0%));
    opacity: 0.55;
}

/* --- The entry hero -------------------------------------------------------- */

/* A detail page's first screen: the thing's face (or its plate) beside its
   facts and the short reading. One shape for all five traditions, so that
   somebody who has seen a rune page recognises a hexagram page. */
.kn-hero,
.entry-hero {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-5);
    align-items: start;
}

@media (min-width: 46rem) {
    .kn-hero,
    .entry-hero {
        grid-template-columns: 13.5rem minmax(0, 1fr);
        gap: var(--space-6);
    }
}

.kn-hero__plate,
.entry-hero__plate {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    justify-items: center;
    width: min(100%, 13.5rem);
    margin-inline: auto;
}

.kn-hero__body,
.entry-hero__body {
    min-width: 0;
}

.kn-hero__title,
.entry-hero__title {
    font-family: var(--font-serif);
    font-size: var(--text-3xl);
    font-weight: 390;
    line-height: 1.12;
    letter-spacing: -0.02em;
    text-wrap: balance;
}

/* =============================================================================
   Styleguide chrome (/dev/styleguide only — dev environment)
   ============================================================================= */

.sg-section {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-4);
    padding-block: var(--space-6);
    border-top: 1px solid var(--color-border-soft);
}

.sg-note {
    max-width: 68ch;
    font-size: var(--text-base);
    line-height: 1.75;
    color: var(--color-muted);
}

.sg-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    gap: var(--space-4);
}

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

.sg-specimen {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-3);
    padding: var(--space-4);
    background: rgb(3 8 18 / 55%);
    border: 1px dashed var(--color-border-soft);
    border-radius: var(--radius-sm);
}

/* The user menu is demonstrated open, and its panel is absolutely positioned, so
   the specimen needs a floor under it — otherwise the panel hangs over whatever
   comes next. `flex-start` keeps the <details> the height of its chip; stretched,
   the panel would open below the stage instead of inside it. */
.sg-menu-stage {
    display: flex;
    align-items: flex-start;
    justify-content: flex-end;
    min-height: 380px;
}

.sg-specimen__label {
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    color: var(--color-muted);
}

.sg-swatch {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-1);
}

.sg-swatch__chip {
    height: 3.5rem;
    border: 1px solid var(--color-border-soft);
    border-radius: var(--radius-sm);
}

.sg-swatch__name {
    font-size: var(--text-sm);
    color: var(--color-text);
}

.sg-swatch__value {
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    color: var(--color-muted);
}

/* =============================================================================
   Responsive chrome

   Three breakpoints, and each one is a decision rather than a device:

     1500px — below this the header stops being able to hold the mockup's
              hand-tuned nav spacing, so it falls back to a flex row.
     1180px — below this seven nav items plus a button no longer fit at any
              readable size, so the `<details>` menu takes over.
      760px — below this the header shrinks and the wordmark with it.
   ============================================================================= */

@media (min-width: 1501px) {
    /* The mockup positions the nav by hand against the engraved header art.
       These offsets are what makes the items sit between the flourishes rather
       than on top of them; they are cosmetic and only apply where there is
       room for the art to be drawn at full size. */
    .site-header__inner {
        transform: translate(45px, 5px);
    }

    .site-header__inner .brand {
        transform: translate(-15px, -5px);
    }

    .site-header__inner .main-nav {
        position: absolute;
        inset-block-start: 22px;
        inset-inline-start: 276px;
        gap: 0;
    }

    .main-nav > :nth-child(2) { margin-inline-start: 34px; }
    .main-nav > :nth-child(3) { margin-inline-start: 42px; }
    .main-nav > :nth-child(4) { margin-inline-start: 40px; }
    .main-nav > :nth-child(5) { margin-inline-start: 45px; }
    .main-nav > :nth-child(6) { margin-inline-start: 44px; }
    .main-nav > :nth-child(7) { margin-inline-start: 45px; }
    .main-nav > :nth-child(8) { margin-inline-start: 37px; }
}

@media (max-width: 1500px) {
    .site-header__inner {
        gap: 24px;
    }

    .main-nav {
        gap: 20px;
    }

    .main-nav__link {
        font-size: 11px;
    }

    .button--header,
    .btn--header {
        min-width: 145px;
    }
}

@media (max-width: 1180px) {
    /* Both the signed-out nav and the signed-in one give way to the hamburger
       here. `.site-nav` was missing from this rule, so on a phone the signed-in
       header showed its full wide nav (wrapped to a second row by the 90rem
       rule) *and* the hamburger at once. */
    .main-nav,
    .site-nav {
        display: none;
    }

    /* `position: static`, not relative: the panel is then anchored to the
       positioned header inner (both `.site-header__inner` and
       `.app-header__inner` are relative) rather than to the hamburger. The
       hamburger is no longer the last thing in the row — an account or login
       chip trails it — so a panel right-aligned to the hamburger would open off
       the left of the screen. Right-aligned to the header content edge, it
       always lands inside the viewport. */
    .mobile-nav {
        position: static;
        display: block;
    }

    .mobile-nav summary {
        position: relative;
        display: grid;
        grid-template-columns: minmax(0, 1fr);
        place-items: center;
        width: 46px;
        height: 46px;
        cursor: pointer;
        list-style: none;
        background: rgb(22 17 35 / 88%);
        border: 1px solid var(--color-border);
        border-radius: var(--radius-control);
    }

    .mobile-nav summary::-webkit-details-marker {
        display: none;
    }

    .mobile-nav summary span,
    .mobile-nav summary span::before,
    .mobile-nav summary span::after {
        display: block;
        width: 20px;
        height: 1px;
        background: var(--color-gold-light);
        transition: transform var(--transition-fast), opacity var(--transition-fast);
    }

    .mobile-nav summary span::before,
    .mobile-nav summary span::after {
        position: absolute;
        content: '';
    }

    .mobile-nav summary span::before {
        transform: translateY(-7px);
    }

    .mobile-nav summary span::after {
        transform: translateY(7px);
    }

    .mobile-nav[open] summary span {
        background: transparent;
    }

    .mobile-nav[open] summary span::before {
        transform: rotate(45deg);
    }

    .mobile-nav[open] summary span::after {
        transform: rotate(-45deg);
    }

    .mobile-nav__panel {
        position: absolute;
        inset-block-start: calc(100% + 4px);
        inset-inline-end: 0;
        z-index: 40;
        display: grid;
        grid-template-columns: minmax(0, 1fr);
        width: min(310px, calc(100vw - 32px));
        max-height: min(70vh, 34rem);
        padding: 12px;
        overflow-y: auto;
        background: rgb(7 10 20 / 98%);
        border: 1px solid var(--color-border);
        border-radius: 9px;
        box-shadow: 0 18px 50px rgb(0 0 0 / 48%);
    }

    .mobile-nav__panel > a:not(.button):not(.btn) {
        display: flex;
        gap: var(--space-2);
        align-items: center;
        min-height: 43px;
        padding-inline: 12px;
        font-size: 12px;
        font-weight: 550;
        color: #dedad5;
        text-transform: uppercase;
        letter-spacing: 0.1em;
        border-radius: var(--radius-sm);
    }

    .mobile-nav__panel > a:not(.button):not(.btn):hover,
    .mobile-nav__panel > a[aria-current='page'] {
        color: var(--color-accent-text);
        background: rgb(119 67 125 / 12%);
    }

    .mobile-nav__panel .button,
    .mobile-nav__panel .btn {
        margin-block-start: 9px;
    }

    /* The small brass heading over each stacked service group — the phone's
       answer to the desktop mega's `.section-label`. First one sits tight to the
       panel edge; the rest get air above them to read as a new group. */
    .mobile-nav__panel .mobile-nav__group {
        margin: 14px 12px 3px;
        font-size: 10px;
        font-weight: 650;
        color: var(--color-accent-text);
        text-transform: uppercase;
        letter-spacing: 0.16em;
    }

    .mobile-nav__panel > .mobile-nav__group:first-child {
        margin-block-start: 2px;
    }
}

@media (max-width: 760px) {
    .site-header {
        height: 72px;
        background-size: 180px auto, 170px auto;
    }

    .site-header__inner {
        width: min(100% - 28px, var(--header-width));
    }

    .brand {
        width: 195px;
        height: 49px;
        transform: translateX(-8px);
    }

    .site-header .brand {
        width: 195px;
        height: 49px;
    }

    .app-header .brand {
        width: 150px;
        height: 38px;
    }

    /* The chip must stay on the first row next to the logotype and the hamburger.
       With the header s 20px column gap it does not fit at 320px, wraps to a row
       of its own on the left, and opens its right-aligned panel off the side of
       the screen. Eight pixels of gap buy the row back. */
    .app-header__inner {
        column-gap: 12px;
    }

    /* The balance is the first thing to go: on a phone the header is a logotype,
       a hamburger and whatever fits between them, and the avatar alone still
       says "you are signed in". The number is one tap away inside the panel,
       twice. */
    .user-menu__balance {
        display: none;
    }

    .user-menu__chip {
        padding-inline: var(--space-2);
    }

    .site-footer__motto::before,
    .site-footer__motto::after {
        display: none;
    }

    .site-footer__motto {
        font-size: 9px;
        letter-spacing: 0.16em;
    }

    .site-footer__motto span {
        margin-inline: 7px;
    }

    .theme-row {
        grid-template-columns: minmax(0, 1fr) 3rem;
    }

    .theme-row__bar {
        grid-column: 1 / -1;
    }
}

@media (max-width: 390px) {
    .brand {
        width: 180px;
        height: 45px;
    }

    .site-header .brand {
        width: 180px;
        height: 45px;
    }

    .mobile-nav summary {
        width: 42px;
        height: 42px;
    }

    /* The chip is a fourth thing in a header that already carries a logotype and
       a hamburger, and at 320px the four of them do not fit at full size. The
       logotype is what gives — it is the one of the four that still reads at
       150px — and :has() scopes it, so a signed-out header, which has three
       things and room for them, is left exactly as it was. */
    .site-header__inner:has(.user-menu) {
        gap: 12px;
    }

    .site-header__inner:has(.user-menu) .brand {
        width: 150px;
        height: 38px;
    }
}
