/* The home screen: its layout and action bar, the site with its structures, the build panel, the plot sheet, the
   site-complete card and the friends bar.
   index.html loads the stylesheets in a fixed order (Game/docs/ui-style.md, "Stylesheets"). */

/* The home screen fills the shell's height (the shell is the only scroll surface), and the site's stage takes the height
   that the other rows leave, so the action bar is on a 390 × 844 screen without scrolling. The development panel and
   the facts for testers follow below the screen (.rj-home__below). */
.rj-home {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    min-height: 100%;
}

.rj-home__top {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

/* The portrait and name on the left, the game's title, and the History button on the right, in one row. */
.rj-home__heading {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.rj-home__heading > .rj-profile {
    flex: 1 1 auto;
    min-width: 0;
}

.rj-home__title {
    flex: 0 1 auto;
    min-width: 0;
    margin: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: var(--ui-font-display);
    font-size: 1.3rem;
    font-weight: 400;
    color: var(--theme-accent, var(--gold-light));
    -webkit-text-stroke: 0.2em var(--ui-outline);
    paint-order: stroke fill;
    text-shadow: 0 0.09em 0 var(--ui-outline);
}

/* The History button: a nav item on its own small panel. */
.rj-hud-btn {
    flex: none;
    width: 3.4rem;
    min-height: 3.2rem;
    border: var(--ui-border) solid var(--ui-outline);
    border-radius: 0.95rem;
    background: linear-gradient(180deg, var(--ui-nav-light) 0%, var(--ui-nav) 55%);
    box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.25), 0 3px 0 var(--ui-outline);
}

.rj-hud-btn .rj-bnav__icon {
    width: 1.6rem;
    height: 1.6rem;
}

.rj-hud-btn .rj-bnav__label { font-size: 0.72rem; }

/* The site's name: a small Ribbon over the top left corner of the site, which is narrower than the stage when the stage
   is short. The left offset leaves room for the ribbon's folded tail. The font size follows the stage's width, so a long
   name ("1968 concrete block, Kontula") fits at 360 px. */
.rj-home__site.rj-ribbon {
    position: absolute;
    z-index: 2;
    top: 0.45rem;
    left: calc((100cqw - var(--site-w)) / 2 + 1rem);
    max-width: calc(var(--site-w) - 2rem);
    min-height: 1.75rem;
    padding: 0.1rem 0.75rem 0.2rem;
    font-size: clamp(0.8rem, 4.2cqw, 1.05rem);
    pointer-events: none;
}

.rj-home__site.rj-ribbon::before,
.rj-home__site.rj-ribbon::after {
    width: 0.85rem;
    bottom: -0.35rem;
}

.rj-home__site.rj-ribbon::before { left: -0.6rem; }
.rj-home__site.rj-ribbon::after  { right: -0.6rem; }

/* The first-session hint: a light Tooltip bubble in the page flow above the site's stage, so it never covers a plot. Its
   tail is towards the site, and an animation moves the bubble up and down by 3 px until the player spins or builds. */
.rj-home__hint.rj-tip {
    align-self: center;
    max-width: 100%;
    margin: 0 0 0.3rem;
    padding: 0.4rem 0.85rem;
    font-size: 0.86rem;
    line-height: 1.2;
    animation: rj-ui-pop 0.35s var(--ui-pop) both, rj-home-hint-bob 2.4s ease-in-out 0.6s infinite;
}

@keyframes rj-home-hint-bob {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-3px); }
}

@media (prefers-reduced-motion: reduce) {
    .rj-home__hint.rj-tip { animation: none; }
}

/* The line on a finished last site: a small framed banner in the primary colour with white display text. */
.rj-home__complete {
    margin: 0;
    padding: 0.35rem 0.8rem 0.45rem;
    border: var(--ui-border) solid var(--ui-outline);
    border-radius: 0.9rem;
    background: linear-gradient(180deg, var(--ui-primary-light) 0%, var(--ui-primary) 55%, color-mix(in srgb, var(--ui-primary) 80%, var(--ui-primary-dark)) 100%);
    box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.4), inset 0 -3px 0 var(--ui-primary-dark), 0 3px 0 var(--ui-outline);
    color: #ffffff;
    font-family: var(--ui-font-display);
    font-size: 0.95rem;
    font-weight: 400;
    line-height: 1.2;
    text-align: center;
    -webkit-text-stroke: 0.18em var(--ui-outline);
    paint-order: stroke fill;
}

/* The action bar: a pending attack or raid, Build and Spin, and the links to the other screens. The bar is the last row
   of the home screen, and it sticks to the bottom of the screen when the home screen is taller than the screen. */
/* The bar's top padding holds the part of the Spin button that stands above the bottom navigation, so the bar's box
   covers the whole button. */
.rj-home__bar {
    position: sticky;
    bottom: 0;
    z-index: 5;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    padding: 0.95rem 0 0.15rem;
}

/* The pending attack and raid: big buttons with the symbol art and the count badge, side by side. */
.rj-home__pending {
    display: flex;
    gap: 0.6rem;
}

.rj-home__pending > .rj-gbtn {
    flex: 1 1 0;
    min-width: 0;
    padding-inline: 0.5rem;
    font-size: 1rem;
}

/* The Spin button rises from the bar above the row of pending buttons too. */
.rj-home__pending + .rj-bnav { margin-top: 0.85rem; }

/* A short screen, such as a 390 × 844 iPhone with Safari's toolbars (about 390 × 664) or an app's in-app browser: the
   home screen hides the title (the heading stays for screen readers), and it reduces the gaps and the bar, so the site
   keeps more of its height. */
@media (max-height: 760px) {
    .rj-shell:has(> .rj-home) {
        padding-top: calc(env(safe-area-inset-top) + 0.5rem);
    }

    .rj-home {
        gap: 0.3rem;
    }

    .rj-home__title {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip: rect(0 0 0 0);
        white-space: nowrap;
    }

    .rj-home__bar {
        gap: 0.3rem;
        padding-top: 0.75rem;
    }

    .rj-home__pending > .rj-gbtn {
        min-height: 2.75rem;
        font-size: 0.92rem;
    }

    .rj-home__bar .rj-bnav__item { min-height: 2.9rem; }

    .rj-home__bar .rj-bnav__spin { min-height: 3.3rem; margin-top: -0.7rem; }

    .rj-home__pending + .rj-bnav { margin-top: 0.65rem; }

    .rj-hud-btn { min-height: 2.9rem; }

    .rj-home__hint.rj-tip {
        padding: 0.25rem 0.7rem;
        font-size: 0.8rem;
    }

    /* The links, the friends bar's buttons and the action buttons keep their 44 px touch height, so the bars lose their
       padding instead and the site keeps its height. */
    .rj-home__top {
        gap: 0.35rem;
    }

    .rj-home .rj-friends-bar {
        padding-block: 0.1rem;
    }

    .rj-home__site.rj-ribbon {
        top: 0.35rem;
        min-height: 1.55rem;
        padding: 0.05rem 0.6rem 0.15rem;
    }
}

.rj-home__below {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    margin-top: 0.9rem;
}

.rj-home__facts {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 0.3rem 1rem;
    margin: 0.5rem 0 0;
    padding: 0.6rem 0.8rem;
    border-radius: var(--r-panel);
    border: 1px solid color-mix(in srgb, var(--theme-text, white) 8%, transparent);
    font-size: 0.8rem;
}

.rj-home__facts dt {
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--theme-text-muted, var(--ink-3));
}

.rj-home__facts dd {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0;
    font-variant-numeric: tabular-nums;
    color: var(--theme-text, var(--ink));
    /* The player id is the one piece of text a tester copies, so it stays selectable. */
    -webkit-user-select: text;
    user-select: text;
    overflow-wrap: anywhere;
}

.rj-home__dot {
    width: 0.6rem;
    height: 0.6rem;
    border-radius: var(--r-pill);
    background: var(--theme-text-muted, var(--ink-3));
}

.rj-home__dot--connected  { background: var(--theme-success, var(--claim)); }
.rj-home__dot--connecting { background: var(--theme-accent, var(--progress)); }
.rj-home__dot--error      { background: var(--theme-danger, var(--danger)); }

/* The router focuses the page heading after a navigation (FocusOnNavigate in App.razor), so a screen reader starts
   there. The heading is not a control, so it draws no focus ring. */
.rj-home__title:focus {
    outline: none;
}

/* ---------------------------------------------------------------------------
   The site (reference: planning/marketing/stills/football/2-home.png)
   The layout (ThemeLayout.csv) gives each structure's centre and width in percent of the background, so the site keeps
   the background's 9:16 shape and each structure is moved back by half its own size.
   --------------------------------------------------------------------------- */
.rj-site {
    position: relative;
    width: 100%;
    aspect-ratio: 9 / 16;
    overflow: hidden;
    border-radius: var(--r-card);
    box-shadow: var(--shadow-panel);
    container-type: inline-size;
    container-name: site;
}

/* The stage around the site. The page makes the stage a flex item that takes the height the other rows leave. The site
   inside keeps its 9:16 shape. It is as wide as the stage while the stage can show --site-share of the site's height, and
   narrower otherwise. When the site is taller than the stage, the stage shows the band around --site-focus of the site's
   height and clips the rest. SiteView sets both from the layout (SiteFraming): the band from the highest structure to the
   lowest, and on the raid screen to the lowest dig spot. A band smaller than the whole site keeps the site at full width
   on a short phone screen, so its plots stay big enough to tap and label. */
/* --site-w and --site-h hold the site's size inside the stage. The stage's children read them, and the container units
   resolve against the stage, so the site and the labels over it (.rj-home__site) share one size. */
.rj-stage {
    --site-share: 1;
    --site-focus: 0.5;
    --site-w: min(100cqw, 100cqh * 9 / 16 / var(--site-share));
    --site-h: calc(var(--site-w) * 16 / 9);
    position: relative;
    flex: 1 1 0;
    min-height: 13rem;
    container-type: size;
    /* clip, not hidden: a clipping box that is no scroll container, so scrollIntoView never scrolls the site inside it. */
    overflow: clip;
    border-radius: var(--r-card);
}

/* No shadow inside the stage: when the site is narrower than the stage, a shadow would draw grey bands beside it. */
.rj-stage > .rj-site {
    position: absolute;
    z-index: 0;
    left: calc((100cqw - var(--site-w)) / 2);
    top: clamp(min(0px, 100cqh - var(--site-h)), 50cqh - var(--site-focus) * var(--site-h), max(0px, 100cqh - var(--site-h)));
    width: var(--site-w);
    box-shadow: none;
}

/* On the home screen the stage is a framed window onto the site: the theme's dark outline, a lift shadow, and an inner
   light rim with a soft dark edge drawn over the art by ::after. The ::after takes no pointer events. The bands beside a
   site that is narrower than the stage take a dark tint of the outline. The rules select the home screen's stage only. */
.rj-home .rj-stage {
    border-radius: var(--ui-radius-panel);
    background: color-mix(in srgb, var(--ui-outline) 40%, transparent);
    box-shadow:
        0 0 0 var(--ui-border) var(--ui-outline),
        0 5px 0 var(--ui-border) color-mix(in srgb, var(--ui-outline) 55%, transparent),
        0 10px 22px var(--ui-shadow);
}

.rj-home .rj-stage::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
    border-radius: inherit;
    box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.28), inset 0 -10px 18px -6px rgba(0, 0, 0, 0.35), inset 0 8px 14px -8px rgba(0, 0, 0, 0.3);
    pointer-events: none;
}

/* The build panel over the bottom of the home screen, outside the site's stage: it covers the action bar and the lower
   part of the stage, and it can grow to the screen's height less the top bar, so at 360 × 640 all five rows show without
   a scroll and no row sits under the Spin button. The panel scrolls when it is taller than that. The screen (#app) is the
   containing block of a fixed element, also inside the desktop phone frame. */
.rj-home > .rj-build {
    position: fixed;
    z-index: 30;
    left: var(--pad);
    right: var(--pad);
    bottom: calc(0.75rem + var(--safe-b));
    max-height: calc(100% - 8rem - var(--safe-b));
    box-sizing: border-box;
    overflow-y: auto;
    overscroll-behavior: contain;
}

/* A count badge sits a little outside its button's corner, so with the panel over the action bar the badge of a button
   under the panel would show beside the panel's edge. */
.rj-home:has(> .rj-build) .rj-home__bar .rj-count-badge { visibility: hidden; }

/* The tags on the home screen's plots, in front of every structure: the structure's name in small display text over a
   price badge with the coin art and the cost. A tag takes no pointer events; site-taps.js sends a tap inside a tag to the
   tag's structure. The font size follows the site's width (the site is an inline-size container), so the tags keep their
   size relative to the plots. SiteView writes the verb ("Build", "Set up") for the tests, and we hide it on a build tag,
   because the price badge already says what a tap does; a repair tag shows its verb on a red badge. */
.rj-site__tags {
    position: absolute;
    inset: 0;
    z-index: 1100;
    pointer-events: none;
}

.rj-plot-tag {
    position: absolute;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.12em;
    max-width: 32cqw;
    /* --tag-shift moves a tag off a level badge it would cover (site-taps.js). */
    transform: translate(-50%, calc(-50% + var(--tag-shift, 0px)));
    font-size: clamp(0.6rem, 3cqw, 0.8rem);
    line-height: 1.05;
    text-align: center;
    pointer-events: none;
    filter: drop-shadow(0 2px 2px rgba(0, 0, 0, 0.35));
}

/* A name breaks only between words. */
.rj-plot-tag__name {
    font-family: var(--ui-font-display);
    font-weight: 400;
    letter-spacing: 0.01em;
    color: #ffffff;
    -webkit-text-stroke: 0.24em var(--ui-outline);
    paint-order: stroke fill;
    /* With a tight line height the browser draws the tops of the display font's capitals outside the tag, so we give the
       name a taller line. */
    line-height: 1.3;
    overflow-wrap: normal;
}

/* The price badge: a chunky pill with the coin art over its left end and the cost in display text. */
.rj-plot-tag__action {
    position: relative;
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    column-gap: 0.3em;
    padding: 0.14em 0.55em 0.14em 0.3em;
    border: 2px solid var(--ui-outline);
    border-radius: 999px;
    background: var(--ui-pill-bg);
    box-shadow: inset 0 0 0 1.5px var(--ui-pill-rim), inset 0 -2px 0 rgba(0, 0, 0, 0.18), 0 2px 0 var(--ui-outline);
    font-family: var(--ui-font-display);
    font-size: 1.08em;
    font-weight: 400;
    color: var(--ui-pill-ink);
    -webkit-text-stroke: 0.18em var(--ui-pill-stroke);
    paint-order: stroke fill;
}

.rj-plot-tag--build .rj-plot-tag__verb { display: none; }

.rj-plot-tag__verb,
.rj-plot-tag__cost {
    white-space: nowrap;
}

.rj-plot-tag__cost {
    display: inline-flex;
    align-items: center;
    gap: 0.2em;
    font-variant-numeric: tabular-nums;
}

.rj-plot-tag .rj-cost-icon {
    width: 1.35em;
    height: 1.35em;
    margin-left: -0.55em;
    filter: drop-shadow(0 1px 0 var(--ui-outline));
}

/* On a repair badge the verb comes first, so the coin keeps its place after it. */
.rj-plot-tag--repair .rj-cost-icon { margin-left: 0; }

/* A plot whose cost the player can pay: a green badge in white display text with a bobbing up arrow on its right end. */
.rj-plot-tag.is-affordable .rj-plot-tag__action {
    padding-right: 1.15em;
    background: linear-gradient(180deg, var(--ui-plus-light) 0%, var(--ui-plus) 55%, var(--ui-plus-dark) 100%);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.55), 0 2px 0 var(--ui-outline);
    color: #ffffff;
    -webkit-text-stroke: 0.18em var(--ui-outline);
}

.rj-plot-tag.is-affordable .rj-plot-tag__action::after {
    content: "";
    position: absolute;
    right: 0.22em;
    top: 50%;
    width: 0.8em;
    height: 0.8em;
    margin-top: -0.4em;
    background: #ffffff;
    -webkit-mask: var(--rj-up-arrow) center / contain no-repeat;
    mask: var(--rj-up-arrow) center / contain no-repeat;
    filter: drop-shadow(0 1px 0 var(--ui-outline));
    animation: rj-up-bob 1s ease-in-out infinite;
}

/* We draw a repair badge red also when the player can pay for it, so the player still sees the damage; it gets the up
   arrow too. */
.rj-plot-tag--repair .rj-plot-tag__action,
.rj-plot-tag--repair.is-affordable .rj-plot-tag__action {
    background: linear-gradient(180deg, var(--ui-danger-light) 0%, var(--ui-danger) 55%, var(--ui-danger-dark) 100%);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45), 0 2px 0 var(--ui-outline);
    color: var(--ui-on-danger);
    -webkit-text-stroke: 0.18em var(--ui-outline);
}

/* On a site narrower than 300 px (a short phone screen with a madness window), the plots are too close together for
   two-line tags, so a tag shows only its price badge; the build panel and the structure's label keep the name. */
@container site (max-width: 300px) {
    .rj-plot-tag__name {
        display: none;
    }
}

/* On a site narrower than 260 px (a short phone screen with two madness windows), the badges also get smaller. */
@container site (max-width: 260px) {
    .rj-plot-tag {
        font-size: 0.55rem;
    }
}

/* The up arrow of the upgrade cues, as a mask shape: the plot tag's arrow and the level badge's arrow. */
:root {
    --rj-up-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M10 1 19.5 10.5H14V19H6v-8.5H.5z'/%3E%3C/svg%3E");
}

@keyframes rj-up-bob {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-2px); }
}

/* The coin float after a build or repair: the cost rises from the structure's centre in display text and fades. It
   takes no pointer events and draws in front of the tags. */
.rj-plot-floats {
    position: absolute;
    inset: 0;
    z-index: 1200;
    pointer-events: none;
}

.rj-plot-float {
    position: absolute;
    transform: translate(-50%, -50%);
    font-family: var(--ui-font-display);
    font-size: 1.35rem;
    font-weight: 400;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    color: var(--ui-primary-light);
    -webkit-text-stroke: 0.2em var(--ui-outline);
    paint-order: stroke fill;
    text-shadow: 0 0.09em 0 var(--ui-outline);
    opacity: 0;
    animation: rj-plot-float 1.1s ease-out;
}

@keyframes rj-plot-float {
    0%   { opacity: 0; transform: translate(-50%, -50%) scale(0.6); }
    15%  { opacity: 1; transform: translate(-50%, -70%) scale(1.15); }
    30%  { transform: translate(-50%, -100%) scale(1); }
    100% { opacity: 0; transform: translate(-50%, -260%) scale(1); }
}

.rj-site__bg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.rj-site__bg--placeholder {
    background:
        radial-gradient(ellipse 90% 45% at 50% 62%, color-mix(in srgb, var(--theme-primary, var(--claim)) 75%, white 10%) 0 60%, transparent 61%),
        linear-gradient(180deg, color-mix(in srgb, var(--theme-accent, var(--progress)) 35%, var(--theme-background, black)) 0%, var(--theme-background, var(--ground)) 45%, color-mix(in srgb, var(--theme-primary, var(--ground-pool)) 70%, black) 100%);
}

.rj-structure {
    position: absolute;
    display: block;
    /* A tap box of at least 44 × 44 px, centred on the structure, for the narrowest pictures on a short screen. */
    min-width: 2.75rem;
    min-height: 2.75rem;
    padding: 0;
    border: 0;
    background: none;
    transform: translate(-50%, -50%);
    cursor: pointer;
    font: inherit;
    color: inherit;
}

/* A structure that takes no tap lets the tap through to the structure under it: a level 0 plot on the attack screen, or
   every structure with no session. site-taps.js then sends a tap on a site to the topmost structure whose picture is
   opaque at the tap point, not to the front box (known issue K4). */
.rj-structure:disabled { cursor: default; pointer-events: none; }

.rj-structure:focus-visible {
    outline: 3px solid var(--theme-accent, var(--gold));
    outline-offset: 2px;
    border-radius: var(--r-panel);
}

/* The ground shadow: a soft dark ellipse under the structure, about 60 % of its width, at about 35 % opacity
   (planning/art/README.md). The generated art has no shadow, because the colour key removes it. */
.rj-structure__shadow {
    position: absolute;
    left: 20%;
    bottom: 2%;
    width: 60%;
    aspect-ratio: 5 / 1;
    border-radius: 50%;
    background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0.35) 0%, rgba(0, 0, 0, 0.35) 45%, transparent 72%);
    filter: blur(2px);
}

.rj-structure__art {
    position: relative;
    display: block;
    width: 100%;
    height: auto;
}

/* CSS placeholder shapes for a theme without art. */
.rj-structure__art--placeholder {
    aspect-ratio: 1;
    border-radius: 18% 18% 10% 10%;
    background:
        linear-gradient(180deg, transparent 0 22%, color-mix(in srgb, var(--theme-surface, var(--surface)) 70%, white) 22% 100%);
    box-shadow: inset 0 -0.6rem 0 color-mix(in srgb, var(--theme-primary, var(--surface)) 70%, black);
    clip-path: polygon(0 30%, 50% 0, 100% 30%, 100% 100%, 0 100%);
}

.rj-structure--s1 .rj-structure__art--placeholder { background-color: color-mix(in srgb, var(--theme-accent, var(--gold)) 55%, transparent); }
.rj-structure--s2 .rj-structure__art--placeholder { clip-path: polygon(0 20%, 100% 20%, 100% 100%, 0 100%); }
.rj-structure--s3 .rj-structure__art--placeholder { clip-path: polygon(10% 25%, 50% 0, 90% 25%, 90% 100%, 10% 100%); }
.rj-structure--s4 .rj-structure__art--placeholder { clip-path: polygon(35% 0, 65% 0, 65% 60%, 100% 60%, 100% 100%, 0 100%, 0 60%, 35% 60%); }
.rj-structure--s5 .rj-structure__art--placeholder { border-radius: 50% 50% 10% 10%; clip-path: none; }

.rj-structure__art--scaffolding {
    aspect-ratio: 1;
    background:
        repeating-linear-gradient(45deg, transparent 0 14%, color-mix(in srgb, var(--theme-accent, var(--gold)) 80%, black) 14% 18%),
        repeating-linear-gradient(-45deg, transparent 0 14%, color-mix(in srgb, var(--theme-accent, var(--gold)) 80%, black) 14% 18%);
    border: 3px solid color-mix(in srgb, var(--theme-accent, var(--gold)) 80%, black);
    border-radius: 8%;
    opacity: 0.85;
}

.rj-structure__damage {
    position: absolute;
    left: 10%;
    top: 5%;
    width: 80%;
    height: auto;
    pointer-events: none;
}

.rj-structure__damage--placeholder {
    aspect-ratio: 1;
    border-radius: 50%;
    background: radial-gradient(circle, color-mix(in srgb, var(--theme-danger, var(--danger)) 85%, transparent) 0 30%, rgba(40, 40, 40, 0.55) 31% 60%, transparent 61%);
}

/* The level badge: a chunky disc at the structure's lower right, in the primary colour ramp with the dark outline, and the
   level in white display text. */
.rj-structure__badge {
    position: absolute;
    right: 4%;
    bottom: 6%;
    display: grid;
    place-items: center;
    box-sizing: border-box;
    min-width: max(1.45rem, 18%);
    aspect-ratio: 1;
    border: 2px solid var(--ui-outline);
    border-radius: 50%;
    background: radial-gradient(circle at 50% 30%, var(--ui-primary-light) 0%, var(--ui-primary) 55%, var(--ui-primary-dark) 100%);
    box-shadow: inset 0 -2px 0 rgba(0, 0, 0, 0.2), 0 2px 0 var(--ui-outline);
    color: #ffffff;
    font-family: var(--ui-font-display);
    font-size: 0.85rem;
    font-weight: 400;
    line-height: 1;
    -webkit-text-stroke: 0.2em var(--ui-outline);
    paint-order: stroke fill;
}

/* The upgrade cue: on the home screen, the badge of a built structure whose next level the player can pay for gets a
   green ring and a bobbing green up arrow over it, so the player sees which structures one tap upgrades. ::before draws
   the arrow's dark outline and ::after the green arrow inside it. */
.rj-structure.is-affordable .rj-structure__badge {
    box-shadow: inset 0 -2px 0 rgba(0, 0, 0, 0.2), 0 0 0 2px var(--ui-plus), 0 2px 0 2px var(--ui-outline);
}

.rj-structure.is-affordable .rj-structure__badge::before,
.rj-structure.is-affordable .rj-structure__badge::after {
    content: "";
    position: absolute;
    left: 50%;
    -webkit-mask: var(--rj-up-arrow) center / contain no-repeat;
    mask: var(--rj-up-arrow) center / contain no-repeat;
    animation: rj-up-bob-x 1s ease-in-out infinite;
}

.rj-structure.is-affordable .rj-structure__badge::before {
    bottom: 82%;
    width: 1.15rem;
    height: 1.15rem;
    background: var(--ui-outline);
}

.rj-structure.is-affordable .rj-structure__badge::after {
    bottom: calc(82% + 0.2rem);
    width: 0.75rem;
    height: 0.75rem;
    background: linear-gradient(180deg, var(--ui-plus-light), var(--ui-plus) 60%);
}

@keyframes rj-up-bob-x {
    0%, 100% { transform: translate(-50%, 0); }
    50%      { transform: translate(-50%, -3px); }
}

.rj-structure.is-damaged .rj-structure__badge {
    background: radial-gradient(circle at 50% 30%, var(--ui-danger-light) 0%, var(--ui-danger) 55%, var(--ui-danger-dark) 100%);
    color: var(--ui-on-danger);
}

/* The level-up pulse after a build or repair. SiteView swaps the two classes on each build, so the browser starts the
   animation again when the player builds the same structure twice. */
.rj-structure.is-pulse-a .rj-structure__art { animation: rj-structure-pulse-a 0.45s ease-out; }
.rj-structure.is-pulse-b .rj-structure__art { animation: rj-structure-pulse-b 0.45s ease-out; }

@keyframes rj-structure-pulse-a {
    0%   { transform: scale(1); filter: brightness(1); }
    40%  { transform: scale(1.12); filter: brightness(1.35); }
    100% { transform: scale(1); filter: brightness(1); }
}

@keyframes rj-structure-pulse-b {
    0%   { transform: scale(1); filter: brightness(1); }
    40%  { transform: scale(1.12); filter: brightness(1.35); }
    100% { transform: scale(1); filter: brightness(1); }
}

@media (prefers-reduced-motion: reduce) {
    .rj-structure.is-pulse-a .rj-structure__art,
    .rj-structure.is-pulse-b .rj-structure__art,
    .rj-structure.is-affordable .rj-structure__badge::before,
    .rj-structure.is-affordable .rj-structure__badge::after,
    .rj-plot-tag.is-affordable .rj-plot-tag__action::after,
    .rj-plot-float { animation: none; }
}

/* ---------------------------------------------------------------------------
   The build panel: a framed Panel (Game/docs/ui-style.md) with a ribbon title, a round red Close, and one game card per
   structure. The light themes (cats, allotment) have light panels, so their names have no outline.
   --------------------------------------------------------------------------- */
.rj-build {
    display: flex;
    flex-direction: column;
    gap: 0.45rem;
    padding: 0.55rem 0.6rem 0.7rem;
    border: 3px solid var(--ui-panel-border);
    border-radius: var(--ui-radius-panel);
    background: linear-gradient(180deg, var(--ui-panel-light) 0%, var(--ui-panel) 38%);
    box-shadow:
        inset 0 2px 0 rgba(255, 255, 255, 0.28),
        0 0 0 2px var(--ui-outline),
        0 6px 0 2px color-mix(in srgb, var(--ui-outline) 55%, transparent),
        0 12px 24px var(--ui-shadow);
    color: var(--ui-panel-ink);
    --rj-name-stroke: var(--ui-outline);
    --rj-name-ink: #ffffff;
}

[data-theme="cats"] .rj-build,
[data-theme="allotment"] .rj-build,
[data-theme="cats"] .rj-plot-sheet,
[data-theme="allotment"] .rj-plot-sheet {
    --rj-name-stroke: transparent;
    --rj-name-ink: var(--ui-panel-ink);
}

/* The ribbon title in the middle of the head, with room on the right for the round Close. */
.rj-build__head {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 3rem;
    padding: 0 3.2rem 0.3rem;
}

.rj-build__title.rj-ribbon {
    max-width: 100%;
    font-size: 1.1rem;
    white-space: normal;
    text-wrap: balance;
}

.rj-build__head > .rj-close {
    position: absolute;
    top: 0;
    right: 0;
}

/* The round Close of the build panel and the plot sheet: a small red GameButton with a white cross. */
.rj-close {
    flex: none;
    width: 2.75rem;
    height: 2.75rem;
    padding: 0;
    border-radius: 50%;
}

.rj-close::before {
    left: 0.35rem;
    right: 0.35rem;
    border-radius: 50% 50% 40% 40%;
}

.rj-close .rj-close__icon {
    width: 1.25rem;
    height: 1.25rem;
}

.rj-build__list {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* One structure's card: the picture on a tile, the name and the level, and the buy button. */
.rj-build__row {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas:
        "thumb name buy"
        "thumb level buy";
    align-items: center;
    column-gap: 0.55rem;
    row-gap: 0.1rem;
    padding: 0.3rem 0.45rem 0.3rem 0.35rem;
    border: 2px solid color-mix(in srgb, var(--ui-panel-border) 45%, var(--ui-outline));
    border-radius: 0.95rem;
    background: linear-gradient(180deg, color-mix(in srgb, var(--ui-panel-light) 82%, white) 0%, var(--ui-panel-light) 60%);
    box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.22), 0 2px 0 color-mix(in srgb, var(--ui-outline) 45%, transparent);
}

/* The row of the structure the player tapped on the site. */
.rj-build__row.is-selected {
    border-color: var(--ui-primary);
    box-shadow: 0 0 0 2px var(--ui-primary-light), inset 0 2px 0 rgba(255, 255, 255, 0.22), 0 2px 0 color-mix(in srgb, var(--ui-outline) 45%, transparent);
}

/* The tile behind a structure's picture in a build panel row and in the plot sheet's head. */
.rj-build__tile {
    grid-area: thumb;
    display: grid;
    place-items: center;
    width: 2.9rem;
    height: 2.9rem;
    border: 2px solid var(--ui-outline);
    border-radius: 0.75rem;
    background: radial-gradient(circle at 50% 30%, var(--ui-secondary-light) 0%, var(--ui-secondary) 75%);
    box-shadow: inset 0 -3px 0 rgba(0, 0, 0, 0.18), 0 2px 0 var(--ui-outline);
}

.rj-build__row.is-damaged .rj-build__tile {
    background: radial-gradient(circle at 50% 30%, var(--ui-danger-light) 0%, var(--ui-danger) 75%);
}

.rj-build__name {
    grid-area: name;
    min-width: 0;
    font-family: var(--ui-font-display);
    font-size: 1.02rem;
    font-weight: 400;
    line-height: 1.1;
    color: var(--rj-name-ink);
    -webkit-text-stroke: 0.18em var(--rj-name-stroke);
    paint-order: stroke fill;
}

/* The level: the pips and the "Level 2 of 4" text, and the Damaged badge. */
.rj-build__level {
    grid-area: level;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.15rem 0.4rem;
    font-size: 0.72rem;
    font-weight: 800;
    color: var(--ui-panel-ink-2);
}

.rj-pips {
    display: inline-flex;
    gap: 0.18rem;
}

.rj-pips__pip {
    width: 0.62rem;
    height: 0.5rem;
    border: 1.5px solid var(--ui-outline);
    border-radius: 0.2rem;
    background: color-mix(in srgb, var(--ui-outline) 30%, transparent);
}

.rj-pips__pip.is-on {
    background: linear-gradient(180deg, var(--ui-primary-light) 0%, var(--ui-primary) 70%);
}

.rj-build__damaged {
    display: inline-block;
    padding: 0.05rem 0.4rem;
    border: 1.5px solid var(--ui-outline);
    border-radius: 999px;
    background: var(--ui-danger);
    color: var(--ui-on-danger);
    font-family: var(--ui-font-display);
    font-size: 0.7rem;
    font-weight: 400;
    line-height: 1.1;
}

.rj-build__buy,
.rj-build__max {
    grid-area: buy;
}

/* The buy button: a GameButton (primary, or danger to repair) with the verb over the cost. */
.rj-build__buy.rj-gbtn {
    flex-direction: column;
    gap: 0;
    min-width: 5.4rem;
    padding: 0.2rem 0.6rem calc(0.2rem + var(--ui-edge));
    font-size: 0.95rem;
    line-height: 1.05;
}

.rj-build__verb {
    white-space: nowrap;
}

.rj-build__cost {
    display: inline-flex;
    align-items: center;
    gap: 0.2rem;
    font-size: 0.9rem;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* The coin before a cost (CoinIcon.razor): the theme's symbol-coin art, sized for each place. Inside a disabled button
   the art is grey, so the player sees at a glance which costs they cannot pay. A theme without art gets a disc. */
.rj-cost-icon {
    flex: none;
    width: 1.1rem;
    height: 1.1rem;
    object-fit: contain;
    filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.35));
}

.rj-cost-icon--placeholder {
    border: 1.5px solid var(--ui-outline);
    border-radius: 50%;
    background: radial-gradient(circle at 50% 35%, var(--ui-primary-light), var(--ui-primary) 70%);
    filter: none;
}

.rj-build__buy:disabled .rj-cost-icon {
    filter: grayscale(1);
    opacity: 0.7;
}

/* A structure's site picture on its tile. For a structure the player has not built yet, the picture is faded. */
.rj-build__thumb {
    flex: none;
    width: 2.45rem;
    height: 2.45rem;
    object-fit: contain;
    filter: drop-shadow(0 2px 1px rgba(0, 0, 0, 0.35));
}

.rj-build__thumb.is-unbuilt { opacity: 0.55; }

/* A structure at the top level: a gold "Top level" badge in place of the buy button. */
.rj-build__max {
    padding: 0.25rem 0.6rem;
    border: 2px solid var(--ui-outline);
    border-radius: 0.7rem;
    background: linear-gradient(180deg, var(--ui-primary-light) 0%, var(--ui-primary) 60%);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.5), 0 2px 0 var(--ui-outline);
    color: #ffffff;
    font-family: var(--ui-font-display);
    font-size: 0.9rem;
    font-weight: 400;
    white-space: nowrap;
    -webkit-text-stroke: 0.18em var(--ui-outline);
    paint-order: stroke fill;
}

.rj-build__message {
    margin: 0;
    font-weight: 800;
    color: var(--ui-danger);
}

/* The plot sheet: a short bar for one structure at the bottom of the home screen (PlotSheet.razor). Home.razor draws it
   inside the action bar, and the sheet covers the whole bar: it is at least as tall as the bar and grows upwards when its
   content needs more. It is outside the site's stage, so it covers no plot and the player can still see and tap every
   other plot. The sheet is a framed Panel that puts the picture on its tile (when the theme has art), the name and level,
   the buy button and the round Close in one row, and the missing coins under the name. */
.rj-home__bar > .rj-plot-sheet {
    position: absolute;
    z-index: 30;
    left: -1px;
    right: -1px;
    bottom: -1px;
    min-height: calc(100% + 2px);
}

.rj-plot-sheet {
    box-sizing: border-box;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto auto;
    grid-template-areas:
        "thumb heading buy close"
        "thumb missing buy close";
    align-items: center;
    column-gap: 0.5rem;
    padding: 0.35rem 0.4rem 0.35rem 0.5rem;
    border: 3px solid var(--ui-panel-border);
    border-radius: var(--ui-radius-panel);
    background: linear-gradient(180deg, var(--ui-panel-light) 0%, var(--ui-panel) 45%);
    box-shadow:
        inset 0 2px 0 rgba(255, 255, 255, 0.28),
        0 0 0 2px var(--ui-outline),
        0 10px 22px var(--ui-shadow);
    color: var(--ui-panel-ink);
    --rj-name-stroke: var(--ui-outline);
    --rj-name-ink: #ffffff;
    animation: rj-plot-sheet-in 0.2s ease-out both;
}

/* The animation changes only the sheet's opacity, not its position, so the sheet covers the action bar from its first
   frame. */
@keyframes rj-plot-sheet-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* The head's children take their own cells in the bar's grid. */
.rj-plot-sheet__head { display: contents; }
.rj-plot-sheet__heading { grid-area: heading; min-width: 0; }

.rj-plot-sheet__tile { grid-area: thumb; }

.rj-plot-sheet__title {
    margin: 0;
    font-family: var(--ui-font-display);
    font-size: 1.05rem;
    font-weight: 400;
    line-height: 1.1;
    color: var(--rj-name-ink);
    -webkit-text-stroke: 0.18em var(--rj-name-stroke);
    paint-order: stroke fill;
}

.rj-plot-sheet__close { grid-area: close; }

.rj-plot-sheet__level {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.1rem 0.35rem;
    margin: 0.1rem 0 0;
    font-size: 0.7rem;
    font-weight: 800;
    color: var(--ui-panel-ink-2);
}

.rj-plot-sheet__buy.rj-gbtn {
    flex-direction: row;
    gap: 0.3rem;
    min-height: 2.9rem;
    padding-inline: 0.65rem;
    font-size: 1rem;
}

/* The sheet is one row on a 360 px screen, so we show its level as pips only and hide the "Level 2 of 4" text from
   sight, not from screen readers. */
.rj-plot-sheet .rj-build__level-text {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

.rj-plot-sheet__buy,
.rj-plot-sheet .rj-build__max { grid-area: buy; }

.rj-plot-sheet .rj-build__max { text-align: center; }

.rj-plot-sheet__missing,
.rj-plot-sheet .rj-build__message {
    grid-area: missing;
    margin: 0;
    font-size: 0.72rem;
    font-weight: 800;
    line-height: 1.15;
}

.rj-plot-sheet__missing { color: var(--ui-danger); }

/* On a dark panel the danger red is too dark for small text, so the missing coins and the refusal take the light red. */
[data-theme="football"] .rj-plot-sheet__missing,
[data-theme="putki"] .rj-plot-sheet__missing,
[data-theme="space"] .rj-plot-sheet__missing,
[data-theme="football"] .rj-build__message,
[data-theme="putki"] .rj-build__message,
[data-theme="space"] .rj-build__message { color: var(--ui-danger-light); }

@media (prefers-reduced-motion: reduce) {
    .rj-plot-sheet { animation: none; }
}

/* ---------------------------------------------------------------------------
   The site-complete card: a full-screen celebration. An animation turns light rays slowly behind a framed Panel with
   the title on a ribbon, another pops the site-complete art in, NumberCountUp counts the rewards up from 0 in big
   display text, and Continue is a large primary GameButton as wide as the card.
   --------------------------------------------------------------------------- */
.rj-site-complete {
    position: fixed;
    inset: 0;
    z-index: 50;
    display: grid;
    place-items: center;
    padding: 1rem;
    overflow: hidden;
    background: radial-gradient(circle at 50% 45%, color-mix(in srgb, var(--ui-primary) 45%, var(--ui-outline)) 0%, color-mix(in srgb, var(--ui-outline) 88%, transparent) 70%);
}

.rj-site-complete__rays {
    position: absolute;
    left: 50%;
    top: 45%;
    width: 260%;
    aspect-ratio: 1;
    background: repeating-conic-gradient(from 0deg, rgba(255, 255, 255, 0.24) 0deg 9deg, transparent 9deg 22.5deg);
    -webkit-mask: radial-gradient(circle, #000 0%, #000 12%, transparent 50%);
    mask: radial-gradient(circle, #000 0%, #000 12%, transparent 50%);
    transform: translate(-50%, -50%);
    animation: rj-rays-turn 30s linear infinite;
    pointer-events: none;
}

@keyframes rj-rays-turn {
    from { transform: translate(-50%, -50%) rotate(0deg); }
    to   { transform: translate(-50%, -50%) rotate(360deg); }
}

.rj-site-complete__card {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.55rem;
    box-sizing: border-box;
    width: min(22rem, 100%);
    margin-top: 1.2rem;
    padding: 1.9rem 1rem 1rem;
    border: 3px solid var(--ui-panel-border);
    border-radius: var(--ui-radius-panel);
    background: linear-gradient(180deg, var(--ui-panel-light) 0%, var(--ui-panel) 38%);
    box-shadow:
        inset 0 2px 0 rgba(255, 255, 255, 0.28),
        0 0 0 2px var(--ui-outline),
        0 6px 0 2px color-mix(in srgb, var(--ui-outline) 55%, transparent),
        0 16px 32px var(--ui-shadow);
    color: var(--ui-panel-ink);
    text-align: center;
    animation: rj-site-complete-in 0.45s var(--ui-pop) both;
}

@keyframes rj-site-complete-in {
    from { opacity: 0; transform: scale(0.6); }
    to   { opacity: 1; transform: scale(1); }
}

/* The title: a ribbon on the card's top edge. */
.rj-site-complete__title.rj-ribbon {
    position: absolute;
    top: 0;
    left: 50%;
    /* The browser sizes an absolute box at left 50% to half the card, so we give the ribbon its text's width, up to the
       card's. */
    width: max-content;
    max-width: calc(100% - 2.5rem);
    transform: translate(-50%, -55%);
    font-size: 1.35rem;
    white-space: normal;
    text-wrap: balance;
}

/* The art is tall in some themes, so its height is capped by the screen's height and the card fits a 360 × 640 screen. */
.rj-site-complete__art {
    width: auto;
    max-width: 75%;
    height: min(14rem, 34vh);
    object-fit: contain;
    filter: drop-shadow(0 6px 8px rgba(0, 0, 0, 0.35));
    animation: rj-site-complete-art 0.6s var(--ui-pop) 0.15s both;
}

@keyframes rj-site-complete-art {
    from { opacity: 0; transform: scale(0.3) rotate(-8deg); }
    to   { opacity: 1; transform: scale(1) rotate(0deg); }
}

/* A reward: the currency's art and "+12 spins" in big display text, whose number NumberCountUp counts up. */
.rj-site-complete__reward {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    margin: 0;
    font-family: var(--ui-font-display);
    font-size: 1.6rem;
    font-weight: 400;
    line-height: 1.1;
    color: #ffffff;
    -webkit-text-stroke: 0.2em var(--ui-outline);
    paint-order: stroke fill;
    text-shadow: 0 0.09em 0 var(--ui-outline);
}

.rj-site-complete__icon {
    flex: none;
    width: 2.3rem;
    height: 2.3rem;
    object-fit: contain;
    filter: drop-shadow(0 2px 0 var(--ui-outline));
}

.rj-site-complete__amount { font-variant-numeric: tabular-nums; }

.rj-site-complete__next {
    margin: 0;
    font-weight: 800;
    color: var(--ui-panel-ink-2);
}

.rj-site-complete__continue {
    margin-top: 0.3rem;
}

@media (prefers-reduced-motion: reduce) {
    .rj-site-complete__card,
    .rj-site-complete__art,
    .rj-site-complete__rays { animation: none; }
}

/* ---------------------------------------------------------------------------
   The friends bar: a pill-coloured strip with the Friends title in display text, each friend's portrait in a ringed
   circle with the site level on a small badge, and a round + bubble to add friends. With no friends it shows Add friends
   and two empty rings. The strip scrolls sideways when the portraits do not fit.
   --------------------------------------------------------------------------- */
.rj-friends-bar {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.3rem 0.6rem 0.45rem;
    border: var(--ui-border) solid var(--ui-outline);
    border-radius: 1rem;
    background: var(--ui-pill-bg);
    box-shadow: inset 0 0 0 1.5px var(--ui-pill-rim), 0 2px 0 var(--ui-outline);
    overflow-x: auto;
    scrollbar-width: none;
}

.rj-friends-bar__title {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    min-width: 2.75rem;
    min-height: 2.75rem;
    font-family: var(--ui-font-display);
    font-size: 1.05rem;
    font-weight: 400;
    color: #ffffff;
    text-decoration: none;
    -webkit-text-stroke: 0.2em var(--ui-outline);
    paint-order: stroke fill;
    text-shadow: 0 0.09em 0 var(--ui-outline);
}

.rj-friends-bar__title .rj-icon {
    width: 1.6rem;
    height: 1.6rem;
    filter: drop-shadow(0 2px 0 rgba(0, 0, 0, 0.3));
}

.rj-friends-bar__add { flex: none; }

.rj-friends-bar__add .rj-icon {
    width: 0.95rem;
    height: 0.95rem;
}

/* The round + bubble after the portraits. Its label is for screen readers only; the link carries an aria-label. */
.rj-friends-bar__add--bubble.rj-gbtn {
    width: 2.75rem;
    height: 2.75rem;
    padding: 0 0 var(--ui-edge);
    border-radius: 50%;
}

.rj-friends-bar__add--bubble.rj-gbtn::before {
    left: 0.35rem;
    right: 0.35rem;
    border-radius: 50% 50% 40% 40%;
}

.rj-friends-bar__add--bubble .rj-gbtn__text { display: none; }

.rj-friends-bar__add--bubble .rj-icon {
    width: 1.2rem;
    height: 1.2rem;
}

.rj-friends-bar__list {
    display: flex;
    gap: 0.55rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.rj-friends-bar__friend {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding-bottom: 0.45rem;
}

.rj-friends-bar__portrait {
    width: 2.35rem;
    height: 2.35rem;
    background: radial-gradient(circle at 50% 35%, var(--ui-secondary-light) 0%, var(--ui-secondary) 80%);
    box-shadow: 0 0 0 2px var(--ui-primary-light), 0 0 0 4px var(--ui-outline);
}

/* The site level on a small badge over the bottom of the portrait's ring. */
.rj-friends-bar__site {
    position: absolute;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    padding: 0 0.3rem;
    border: 1.5px solid var(--ui-outline);
    border-radius: 999px;
    background: linear-gradient(180deg, var(--ui-primary-light) 0%, var(--ui-primary) 70%);
    color: #ffffff;
    font-family: var(--ui-font-display);
    font-size: 0.6rem;
    font-weight: 400;
    line-height: 1.25;
    white-space: nowrap;
    -webkit-text-stroke: 0.2em var(--ui-outline);
    paint-order: stroke fill;
}

/* The empty rings of a bar with no friends: where friends will appear. */
.rj-friends-bar__slots {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    min-height: 2.75rem;
    text-decoration: none;
}

.rj-friends-bar__slot {
    box-sizing: border-box;
    width: 2.35rem;
    height: 2.35rem;
    border: 2.5px dashed color-mix(in srgb, var(--ui-pill-ink) 45%, transparent);
    border-radius: 50%;
    background: color-mix(in srgb, var(--ui-pill-ink) 8%, transparent);
}
