/* Hexux theme layer.
   Overrides Bootstrap 5.3's own CSS variables rather than adding rules that
   fight it, so components pick the theme up without extra classes. */

:root,
[data-bs-theme="light"] {
    --bs-primary: #7048e8;
    --bs-primary-rgb: 112, 72, 232;
    --bs-link-color: #5f3dc4;
    --bs-link-color-rgb: 95, 61, 196;
    --bs-link-hover-color: #4c2fa8;

    /* Warm neutrals rather than Bootstrap's cool greys. */
    --bs-body-bg: #f7f5f2;
    --bs-body-color: #2b2431;
    --bs-secondary-color: #6b6577;
    --bs-border-color: #e6e1dc;

    --hx-surface: #ffffff;
    --hx-surface-muted: #f2eeea;
    --hx-shadow: 0 1px 2px rgba(28, 20, 40, .04), 0 8px 24px rgba(28, 20, 40, .06);
    --hx-shadow-hover: 0 2px 4px rgba(28, 20, 40, .06), 0 12px 32px rgba(28, 20, 40, .10);
    --hx-radius: 14px;
}

[data-bs-theme="dark"] {
    --bs-primary: #9775fa;
    --bs-primary-rgb: 151, 117, 250;
    --bs-link-color: #b197fc;
    --bs-link-color-rgb: 177, 151, 252;
    --bs-link-hover-color: #d0bfff;

    /* Warm-tinted dark, not blue-black. */
    --bs-body-bg: #17151a;
    --bs-body-color: #ece9f0;
    --bs-secondary-color: #a49eb0;
    --bs-border-color: #302b38;

    --hx-surface: #211e26;
    --hx-surface-muted: #2a2530;
    --hx-shadow: 0 1px 2px rgba(0, 0, 0, .3), 0 8px 24px rgba(0, 0, 0, .25);
    --hx-shadow-hover: 0 2px 4px rgba(0, 0, 0, .35), 0 12px 32px rgba(0, 0, 0, .35);
}

body {
    background: var(--bs-body-bg);
    color: var(--bs-body-color);
    -webkit-font-smoothing: antialiased;
}

/* ---------- layout ---------- */

.hx-main {
    max-width: 42rem;
}
.hx-main-wide {
    max-width: 64rem;
}

/* ---------- cards ---------- */

.hx-card {
    background: var(--hx-surface);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--hx-radius);
    box-shadow: var(--hx-shadow);
    padding: 1rem 1.15rem;
    margin-bottom: .9rem;
    transition: box-shadow .18s ease, transform .18s ease;
}
.hx-card:hover {
    box-shadow: var(--hx-shadow-hover);
}

/* ---------- composer ---------- */

.hx-composer-input {
    border: 0;
    background: transparent;
    padding: .35rem 0;
    resize: vertical;
    min-height: 3rem;
    font-size: 1.02rem;
}
.hx-composer-input:focus {
    background: transparent;
    box-shadow: none;
    border: 0;
}
.hx-composer:focus-within {
    border-color: rgba(var(--bs-primary-rgb), .45);
}

/* ---------- dropdown ---------- */

.dropdown-menu {
    background: var(--hx-surface);
    border: 1px solid var(--bs-border-color);
    border-radius: 12px;
    box-shadow: var(--hx-shadow);
    padding: .35rem;
}
.dropdown-item {
    border-radius: 8px;
    padding: .45rem .7rem;
}
.dropdown-item:hover, .dropdown-item:focus {
    background: var(--hx-surface-muted);
    color: var(--bs-body-color);
}

/* ---------- avatars ---------- */

.hx-avatar {
    border-radius: 50%;
    object-fit: cover;
    flex: 0 0 auto;
    background: var(--hx-surface-muted);
}
.hx-avatar-sm { width: 34px; height: 34px; }
.hx-avatar-md { width: 46px; height: 46px; }
.hx-avatar-lg { width: 104px; height: 104px; }

/* ---------- posts ---------- */

.hx-post-head {
    display: flex;
    align-items: center;
    gap: .65rem;
    margin-bottom: .5rem;
}
.hx-post-author {
    font-weight: 600;
    text-decoration: none;
    color: var(--bs-body-color);
}
.hx-post-author:hover { color: var(--bs-link-color); }
.hx-post-meta {
    font-size: .82rem;
    color: var(--bs-secondary-color);
}
.hx-post-body {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    line-height: 1.55;
}
.hx-post-actions {
    display: flex;
    align-items: center;
    gap: .4rem;
    flex-wrap: wrap;
    margin-top: .75rem;
}

/* Quiet action buttons that only gain weight on hover. */
.hx-action {
    --bs-btn-border-color: transparent;
    --bs-btn-hover-border-color: transparent;
    border-radius: 999px;
    font-size: .84rem;
    padding: .3rem .7rem;
    color: var(--bs-secondary-color);
    background: transparent;
    border: 1px solid transparent;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: .35rem;
}
.hx-action:hover {
    background: var(--hx-surface-muted);
    color: var(--bs-body-color);
}
.hx-action-like.is-liked,
.hx-action-like.is-liked:hover {
    color: #e8590c;
}
.hx-action-danger:hover {
    color: #c92a2a;
}

/* ---------- navbar ---------- */

.navbar.hx-nav {
    background: var(--hx-surface);
    border-bottom: 1px solid var(--bs-border-color);
    backdrop-filter: saturate(1.4) blur(6px);
}
.hx-brand {
    font-weight: 700;
    letter-spacing: -.02em;
    color: var(--bs-body-color) !important;
}
.hx-brand-accent { color: var(--bs-primary); }
.hx-nav .nav-link {
    border-radius: 999px;
    padding: .4rem .8rem !important;
    color: var(--bs-secondary-color);
}
.hx-nav .nav-link:hover {
    background: var(--hx-surface-muted);
    color: var(--bs-body-color);
}
.hx-nav .nav-link.active {
    background: rgba(var(--bs-primary-rgb), .12);
    color: var(--bs-primary);
    font-weight: 600;
}

/* ---------- forms ---------- */

.form-control, .form-select {
    background: var(--hx-surface);
    border-color: var(--bs-border-color);
    border-radius: 10px;
    padding: .55rem .8rem;
}
.form-control:focus, .form-select:focus {
    border-color: var(--bs-primary);
    box-shadow: 0 0 0 .2rem rgba(var(--bs-primary-rgb), .18);
}
.btn { border-radius: 10px; }
.btn-primary {
    --bs-btn-bg: var(--bs-primary);
    --bs-btn-border-color: var(--bs-primary);
    --bs-btn-hover-bg: #5f3dc4;
    --bs-btn-hover-border-color: #5f3dc4;
}

/* ---------- chat ---------- */

.hx-thread {
    background: var(--hx-surface);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--hx-radius);
    /* Viewport-relative with a floor and ceiling, so it fits a phone in
       landscape as well as a desktop. */
    height: clamp(16rem, 55vh, 34rem);
    overflow-y: auto;
    padding: 1rem;
}
.hx-bubble {
    display: inline-block;
    max-width: min(80%, 34rem);
    padding: .5rem .8rem;
    border-radius: 16px;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    text-align: left;
    line-height: 1.45;
}
.hx-bubble-mine {
    background: var(--bs-primary);
    color: #fff;
    border-bottom-right-radius: 5px;
}
.hx-bubble-theirs {
    background: var(--hx-surface-muted);
    color: var(--bs-body-color);
    border-bottom-left-radius: 5px;
}

/* ---------- chat media ---------- */

.hx-media { display: block; }
.hx-media-img,
.hx-media-video {
    max-width: min(100%, 20rem);
    max-height: 20rem;
    border-radius: 12px;
    border: 1px solid var(--bs-border-color);
    display: inline-block;
    background: var(--hx-surface-muted);
}
.hx-media-img { cursor: zoom-in; object-fit: cover; }
.hx-media-video { width: min(100%, 20rem); }

@media (max-width: 576px) {
    .hx-media-img, .hx-media-video { max-width: 100%; max-height: 15rem; }
}

/* ---------- map ---------- */

#map {
    height: clamp(18rem, 60vh, 40rem);
    border-radius: var(--hx-radius);
    border: 1px solid var(--bs-border-color);
}
.cell-label {
    background: transparent;
    border: 0;
    box-shadow: none;
    font-weight: 600;
    color: var(--bs-body-color);
}
.cell-label::before { display: none; }

/* ---------- hover card ---------- */

/* Bootstrap's popover reads these, so the card follows light/dark with the
   rest of the theme instead of staying stock white. */
.popover {
    --bs-popover-bg: var(--hx-surface);
    --bs-popover-border-color: var(--bs-border-color);
    --bs-popover-body-color: var(--bs-body-color);
    --bs-popover-max-width: 20rem;
    --bs-popover-border-radius: 12px;
    --bs-popover-inner-border-radius: 12px;
    box-shadow: var(--hx-shadow-hover);
}
.popover-body { padding: .8rem .9rem; }

.hx-popup {
    /* Bounded so a long bio or username cannot stretch the card. */
    min-width: 14rem;
    max-width: 18rem;
}
.hx-popup img { flex: 0 0 auto; }
.hx-popup-name {
    display: block;
    font-weight: 600;
    text-decoration: none;
    color: var(--bs-body-color);
    overflow-wrap: anywhere;
}
.hx-popup-name:hover { color: var(--bs-link-color); }
.hx-popup-meta {
    font-size: .78rem;
    color: var(--bs-secondary-color);
    line-height: 1.35;
}
.hx-popup-bio {
    font-size: .86rem;
    margin: 0 0 .5rem;
    /* Trim a long bio rather than letting it grow the card. */
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
    overflow-wrap: anywhere;
}
.hx-popup-stats {
    display: flex;
    flex-wrap: wrap;
    gap: .75rem;
    font-size: .82rem;
    color: var(--bs-secondary-color);
}

/* ---------- misc ---------- */

.hx-stat {
    background: var(--hx-surface);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--hx-radius);
    padding: 1rem;
    text-align: center;
}
.hx-stat-value {
    font-size: 1.6rem;
    font-weight: 700;
    line-height: 1.1;
}
.list-group-item { background: var(--hx-surface); }

/* ---------- mobile ---------- */

@media (max-width: 576px) {
    .hx-card { padding: .85rem .9rem; border-radius: 12px; }
    .hx-avatar-lg { width: 72px; height: 72px; }
    /* Comfortable tap targets. */
    .hx-action { padding: .45rem .75rem; }
    .hx-nav .nav-link { padding: .55rem .8rem !important; }
    h1 { font-size: 1.5rem; }
}

/* Moved out of a <style> block in map.html so no page carries inline CSS. */
.cell-users { margin: 0; padding-left: 1rem; }

/* The withdraw control on your own chat messages. Deliberately quiet: it sits
   beside every message you sent, so it must not compete with the text.
   Quiet, but always there - see the note on hover-to-reveal below. */
.hx-message-delete {
    padding: 0 .35rem;
    line-height: 1;
    color: var(--bs-secondary-color);
    text-decoration: none;
}
.hx-message-delete:hover { color: var(--bs-danger); }

/* Hide-until-hover, for pointers that can actually hover.
   
   This site is used on phones, and a touch screen has no hover: the browser
   fakes one on first tap, so a control hidden this way needs tapping twice -
   once to reveal it and once to press it. That reads as a broken button, and
   it is how Corey found the delete control apparently missing.
   
   `hover: hover` is true only where a pointer can rest on something without
   pressing it. Everywhere else these stay visible, which is the behaviour a
   thread on a phone wants anyway. */
@media (hover: hover) and (pointer: fine) {
    .hx-message-delete,
    .hx-message-report {
        opacity: 0;
        transition: opacity .12s ease-in-out;
    }
    .hx-thread > div:hover .hx-message-delete,
    .hx-thread > div:hover .hx-message-report,
    .hx-message-delete:focus-visible,
    .hx-message-report:focus-visible {
        opacity: 1;
    }
}

.hx-footer hr { opacity: .12; }

/* The privacy policy reads as a document, not as a feed. */
.hx-prose { max-width: 46rem; }
.hx-prose h2 { font-size: 1.15rem; margin-top: 2rem; }
.hx-prose h2:first-of-type { margin-top: 1rem; }
.hx-prose li { margin-bottom: .35rem; }

/* Moved out of a <style> block in edit_profile.html, so no page carries
   inline CSS either. */

/* Hidden by edit-profile.js rather than by default, so the fields stay
   usable if the script does not run. */
#password-fields.is-hidden { display: none; }

/* The preview sits beside its controls rather than above them, so the photo
   and the setting for who may see it read as one thing. Wraps on a narrow
   screen. .picture-icon used to live here as well - an overlay for a camera
   button that no template ever rendered. */
.hx-photo-edit {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    align-items: flex-start;
}
.hx-photo-controls { flex: 1 1 16rem; min-width: 0; }
.profile-picture {
    width: clamp(88px, 22vw, 140px);
    height: clamp(88px, 22vw, 140px);
    border-radius: 50%;
    object-fit: cover;
    border: 1px solid var(--bs-border-color);
}

/* The terms shown on the acceptance gate: scrollable so the Accept and
   Decline buttons stay reachable without paging through the whole document,
   while the text itself stays fully readable. */
.hx-terms-scroll {
    max-height: 24rem;
    overflow-y: auto;
    background-color: var(--bs-tertiary-bg);
}
.hx-terms-scroll h2:first-of-type { margin-top: 1rem; }

/* ---------------------------------------------------------------- reactions */
.hx-reactions { display: inline-flex; flex-wrap: wrap; gap: .25rem; align-items: center; }
.hx-reaction {
    border: 1px solid transparent;
    background: var(--bs-tertiary-bg);
    border-radius: 999px;
    padding: .1rem .5rem;
    font-size: .9rem;
    line-height: 1.4;
    cursor: pointer;
}
.hx-reaction:hover { border-color: var(--bs-border-color); }
.hx-reaction.is-mine {
    border-color: var(--bs-primary);
    background: color-mix(in srgb, var(--bs-primary) 12%, transparent);
}
.hx-reaction-count { font-size: .8rem; color: var(--bs-secondary-color); margin-left: .15rem; }
.hx-reaction.is-mine .hx-reaction-count { color: var(--bs-primary); }
.hx-reaction-add { color: var(--bs-secondary-color); font-weight: 600; }
.hx-reaction-menu { min-width: auto; padding: .35rem; }

/* -------------------------------------------------------------------- polls */
.hx-poll { margin-top: .75rem; display: flex; flex-direction: column; gap: .35rem; }
.hx-poll-option {
    display: block;
    width: 100%;
    text-align: left;
    border: 1px solid var(--bs-border-color);
    background: transparent;
    border-radius: .5rem;
    padding: .4rem .75rem;
    cursor: pointer;
}
.hx-poll-option:hover { border-color: var(--bs-primary); }
/* The bar sits behind the label rather than beside it, so a long option does
   not squash the result out of view on a narrow screen. */
.hx-poll-result {
    position: relative;
    display: flex;
    justify-content: space-between;
    gap: .5rem;
    border-radius: .5rem;
    padding: .4rem .75rem;
    overflow: hidden;
    background: var(--bs-tertiary-bg);
}
.hx-poll-fill {
    position: absolute;
    inset: 0 auto 0 0;
    background: color-mix(in srgb, var(--bs-primary) 18%, transparent);
}
.hx-poll-result.is-mine .hx-poll-fill {
    background: color-mix(in srgb, var(--bs-primary) 32%, transparent);
}
.hx-poll-label, .hx-poll-share { position: relative; }
.hx-poll-share { color: var(--bs-secondary-color); font-variant-numeric: tabular-nums; }
.hx-poll-meta { font-size: .8rem; color: var(--bs-secondary-color); margin: .25rem 0 0; }
.hx-poll-fields.is-hidden { display: none; }

/* ------------------------------------------------------- question of the day */
/* Used on an <a> in the feed and a <div> on the prompt page, so everything it
   needs to look right lives here rather than in utility classes on the tag.
   It previously carried .d-block in the feed, which is display:block
   !important and quietly beat the flex column below - the three lines ran
   together into one, and only on that page. */
.hx-prompt-card {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: .3rem;
    text-decoration: none;
    /* Marks it out from the ordinary post cards it sits above. */
    border-left: 3px solid var(--bs-primary);
}
a.hx-prompt-card .hx-prompt-body { transition: color .15s ease-in-out; }
a.hx-prompt-card:hover .hx-prompt-body { color: var(--bs-primary); }
.hx-prompt-kicker {
    font-size: .7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--bs-primary);
}
.hx-prompt-body {
    font-size: 1.15rem;
    font-weight: 600;
    line-height: 1.35;
    color: var(--bs-body-color);
    overflow-wrap: anywhere;
}
.hx-prompt-tag {
    display: inline-block;
    font-size: .75rem;
    color: var(--bs-secondary-color);
    text-decoration: none;
    margin-bottom: .35rem;
}
.hx-prompt-tag:hover { color: var(--bs-primary); }

/* --------------------------------------------------------- profile questions */
.hx-profile-answers {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: .75rem;
    margin-top: 1rem;
}
.hx-profile-answer {
    background: var(--bs-tertiary-bg);
    border-radius: .5rem;
    padding: .6rem .75rem;
}
.hx-profile-question {
    display: block;
    font-size: .75rem;
    color: var(--bs-secondary-color);
    margin-bottom: .15rem;
}

/* ------------------------------------------------------------------ reports */
.hx-action-report { color: var(--bs-secondary-color); }
.hx-action-report:hover { color: var(--bs-danger); }
/* Quiet, like the delete control beside it: a Report link on every incoming
   message must not read as an invitation. The hide-until-hover half is with
   that rule, scoped to pointers that can hover. */

.hx-report-snapshot {
    background: var(--bs-tertiary-bg);
    border-left: 3px solid var(--bs-border-color);
    border-radius: .35rem;
    padding: .6rem .75rem;
    overflow-wrap: anywhere;
}

/* ------------------------------------------------------------------ beacons */
/* The dot marks something live and time-limited, so it pulses rather than
   sitting still - but only for people who have not asked for less motion. */
.hx-beacon-dot {
    display: inline-block;
    width: .5rem;
    height: .5rem;
    border-radius: 50%;
    background: #e03131;
    margin-right: .3rem;
    vertical-align: baseline;
}
@media (prefers-reduced-motion: no-preference) {
    .hx-beacon-dot { animation: hx-pulse 2s ease-in-out infinite; }
}
@keyframes hx-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: .35; }
}
.hx-beacon { border-left: 3px solid #e03131; }
.hx-beacon-mine { border-left: 3px solid var(--bs-primary); }
.hx-beacon-body { overflow-wrap: anywhere; }
.hx-beacon-inline {
    font-size: .9rem;
    margin-bottom: .35rem;
    overflow-wrap: anywhere;
}

/* A range, not a number - so it should not look like a precise readout. */
.hx-distance { white-space: nowrap; }

/* ------------------------------------------------------------- looking now */
.hx-filters {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    align-items: center;
    margin-bottom: .9rem;
}
.hx-filters .form-select { width: auto; }
.hx-nearby { padding: .75rem .9rem; margin-bottom: .6rem; }
/* Someone who has said they are around now is the reason to open this page,
   so they carry the same accent the beacon list uses. */
.hx-nearby-beacon { border-left: 3px solid #e03131; }
.hx-nearby-about { font-size: .9rem; overflow-wrap: anywhere; }

/* ------------------------------------------------------- profile detail chips */
.hx-profile-details { display: flex; flex-wrap: wrap; gap: .35rem; }
.hx-chip {
    display: inline-block;
    background: var(--bs-tertiary-bg);
    border-radius: 999px;
    padding: .1rem .6rem;
    font-size: .82rem;
}
.hx-chip-strong {
    background: color-mix(in srgb, var(--bs-primary) 14%, transparent);
    color: var(--bs-primary);
}

/* -------------------------------------------------------------- private album */
.hx-album-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: .6rem;
}
.hx-album-item { margin: 0; }
.hx-album-item img {
    width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: cover;
    border-radius: .5rem;
    display: block;
}
.hx-album-item figcaption { text-align: center; margin-top: .2rem; }

/* Health details are shown apart from the other chips: not colour-coded by
   status, which would sort people by it visually, just marked as its own
   thing. */
.hx-chip-health {
    background: var(--bs-tertiary-bg);
    border: 1px solid var(--bs-border-color);
}
.hx-health-fieldset {
    border-left: 3px solid var(--bs-border-color);
    padding-left: .9rem;
}

/* ------------------------------------------------------------- admin panel */
/* Deliberately unlike the member controls above it. Suspend and Delete sitting
   in the same visual language as Follow and Message is how the wrong one gets
   pressed. */
.hx-admin-panel {
    margin-top: 1rem;
    padding: .75rem .9rem;
    border: 1px dashed var(--bs-border-color);
    border-radius: .5rem;
    background: var(--bs-tertiary-bg);
}
.hx-admin-kicker {
    font-size: .7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--bs-secondary-color);
}

/* ------------------------------------------------------- people in search */
.hx-people-results {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: .5rem;
}
.hx-person-card {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .5rem .6rem;
    border: 1px solid var(--bs-border-color);
    border-radius: .5rem;
    text-decoration: none;
    color: inherit;
}
.hx-person-card:hover { border-color: var(--bs-primary); }

/* The walkthrough reads as one thing at a time, so it stays narrow. */
.hx-onboarding { max-width: 34rem; }

/* Multi-select fields rendered as a checkbox grid. A native <select multiple>
   needs ctrl-click to add a second choice, which on a phone means it quietly
   behaves like a single select - so the one control people were most likely
   to use on a phone was the one that worked worst there. */
.hx-tag-grid {
    display: flex;
    flex-wrap: wrap;
    gap: .375rem;
}

.hx-tag-option {
    cursor: pointer;
    margin: 0;
}

.hx-tag-option input {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}

.hx-tag-option span {
    display: inline-block;
    padding: .3rem .7rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 2rem;
    font-size: .875rem;
    line-height: 1.2;
    background: var(--bs-body-bg);
    color: var(--bs-body-color);
    transition: background-color .12s ease, border-color .12s ease;
}

.hx-tag-option input:checked + span {
    background: var(--bs-primary);
    border-color: var(--bs-primary);
    color: #fff;
}

/* Keyboard users get the same affordance as the pointer: without this the
   focus ring is on the hidden input and lands nowhere visible. */
.hx-tag-option input:focus-visible + span {
    outline: 2px solid var(--bs-primary);
    outline-offset: 2px;
}

/* The profile carousel manager. */
.hx-photo-grid {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    margin-bottom: 1rem;
}

.hx-photo-tile {
    position: relative;
    width: 120px;
    height: 120px;
    border-radius: .5rem;
    overflow: hidden;
    cursor: grab;
}

.hx-photo-tile img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.hx-photo-tile.is-dragging {
    opacity: .4;
}

.hx-photo-badge {
    position: absolute;
    left: .25rem;
    bottom: .25rem;
    padding: .1rem .4rem;
    border-radius: .25rem;
    font-size: .7rem;
    background: rgba(0, 0, 0, .65);
    color: #fff;
}

.hx-photo-remove {
    position: absolute;
    top: .25rem;
    right: .25rem;
    width: 1.5rem;
    height: 1.5rem;
    line-height: 1;
    border: 0;
    border-radius: 50%;
    background: rgba(0, 0, 0, .65);
    color: #fff;
    cursor: pointer;
}

/* The carousel as shown on a profile. Horizontal scroll rather than a
   JavaScript slider: it works with a thumb, a trackpad and a keyboard without
   any of them being special-cased. */
.hx-photo-strip {
    display: flex;
    gap: .5rem;
    overflow-x: auto;
    padding-bottom: .5rem;
    scroll-snap-type: x mandatory;
}

.hx-photo-strip a {
    flex: 0 0 auto;
    scroll-snap-align: start;
}

.hx-photo-strip img {
    width: 160px;
    height: 160px;
    object-fit: cover;
    border-radius: .5rem;
    display: block;
}

/* The lock screen. Narrow and centred: it is the only thing on the page, and
   it should not look like the site with the content missing. */
.hx-lock-screen {
    max-width: 22rem;
    margin: 3rem auto;
}

.hx-narrow-form {
    max-width: 24rem;
}

/* ---------- places ---------- */

.hx-place-map {
    height: clamp(14rem, 40vh, 24rem);
    border-radius: var(--hx-radius);
    border: 1px solid var(--bs-border-color);
}
.hx-place-here {
    border-left: 3px solid var(--bs-success);
}
.hx-place-coming {
    border-left: 3px solid var(--bs-warning);
}
.hx-place-faces {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
}
.hx-place-face {
    display: flex;
    align-items: center;
    gap: .4rem;
    padding: .25rem .6rem .25rem .25rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 999px;
    font-size: .875rem;
    text-decoration: none;
}
.hx-place-face img {
    border-radius: 50%;
}

/* Place pins on the map. An emoji in a disc rather than an image sprite:
   nothing to licence, nothing to keep in step with the category list, and a
   new category is drawable the moment it is added. */
.hx-place-pin {
    width: 34px;
    height: 34px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.05rem;
    line-height: 1;
    border-radius: 50%;
    background: var(--bs-body-bg);
    border: 2px solid var(--bs-border-color);
    box-shadow: 0 1px 4px rgb(0 0 0 / 25%);
    position: relative;
}
/* Somewhere with people in it earns a ring, so a busy venue reads at a
   glance without having to click every pin. */
.hx-place-pin.is-busy {
    border-color: var(--bs-success);
}
.hx-place-pin-count {
    position: absolute;
    top: -4px;
    right: -4px;
    min-width: 17px;
    height: 17px;
    padding: 0 4px;
    border-radius: 999px;
    background: var(--bs-success);
    color: #fff;
    font-size: .65rem;
    font-weight: 700;
    line-height: 17px;
    text-align: center;
}
.hx-place-pin-legend {
    width: 22px;
    height: 22px;
    font-size: .8rem;
    display: inline-flex;
    vertical-align: middle;
    box-shadow: none;
}

/* An event that has been called off is still listed until its time passes:
   removing it from the page is how somebody turns up anyway. */
.hx-event-off h2 a {
    text-decoration: line-through;
}
.hx-event-off {
    opacity: .75;
}

/* The follow-me control on the map. */
.hx-follow-icon {
    vertical-align: -2px;
    margin-right: .15rem;
}
#follow.active {
    background: var(--bs-primary);
    border-color: var(--bs-primary);
    color: #fff;
}

/* Voice notes. */
.hx-media-voice {
    max-width: 100%;
    width: 16rem;
}

#voice-record.is-recording {
    background-color: var(--bs-danger);
    border-color: var(--bs-danger);
    color: #fff;
}

/* A view-once photo, shown as something to press rather than a picture: an
   <img> would be fetched by the browser on its own and spend the one look
   before the recipient had chosen to open anything. */
.hx-once {
    display: inline-block;
    padding: .6rem .75rem;
    border: 1px dashed var(--bs-border-color);
    border-radius: .5rem;
    max-width: 16rem;
}

.hx-once.is-spent {
    border-style: solid;
    color: var(--bs-secondary-color);
    font-size: .875rem;
}

/* The screenshot notice. Quiet rather than alarming: it is a standing fact
   about how screens work, not a warning about the person you are talking to,
   and something shouty would be ignored within a week. */
.hx-screenshot-notice {
    font-size: .8125rem;
    color: var(--bs-secondary-color);
    margin: .5rem 0 0;
}

/* Landing page. The only page seen before signing in, so it is wider than the
   signed-in column and reads as a page rather than a feed. Mobile first: the
   grid is one column until there is room for two, and nothing here depends on
   hover. */
.hx-landing {
    max-width: 46rem;
}

.hx-landing-hero {
    padding: 2.5rem 0 1.75rem;
}

.hx-landing-title {
    font-weight: 700;
    letter-spacing: -.02em;
    font-size: clamp(2.25rem, 9vw, 3.25rem);
    margin-bottom: .5rem;
}

.hx-landing-lede {
    font-size: clamp(1.05rem, 3.6vw, 1.3rem);
    color: var(--bs-secondary-color);
    max-width: 30rem;
    margin: 0 auto 1.5rem;
    text-wrap: balance;
}

.hx-landing-cta {
    display: flex;
    flex-direction: column;
    gap: .625rem;
    max-width: 20rem;
    margin: 0 auto;
}

@media (min-width: 30rem) {
    .hx-landing-cta {
        flex-direction: row;
        justify-content: center;
        max-width: none;
    }
    .hx-landing-cta .btn {
        min-width: 11rem;
    }
}

.hx-landing-fineprint {
    margin-top: 1rem;
    font-size: .85rem;
    color: var(--bs-secondary-color);
}

/* The location model is the reason to choose this over anything else, so it
   gets its own card above the grid rather than a quarter of it. */
.hx-landing-lead {
    border-left: 3px solid var(--bs-primary);
}

.hx-landing-grid {
    margin-top: 1rem;
}

.hx-landing-foot {
    margin-top: 1rem;
}

.hx-landing-foot {
    padding: 1.5rem 0 .5rem;
}

/* The install offer. Quiet on purpose - it is an offer, not news, and a
   banner that shouts gets dismissed on reflex by the people who would
   otherwise have taken it. */
.hx-install {
    align-items: flex-start;
}

.hx-install p:last-child {
    margin-bottom: 0;
}

/* A message and its controls on one line.
 *
 * They were a row underneath, which read as a separate thing rather than as
 * belonging to the message - and before that they were loose inline elements
 * that wrapped differently on every message. Beside the bubble, on its right,
 * is where somebody looks for them.
 */
.hx-msg-line {
    display: flex;
    align-items: center;
    gap: .35rem;
    min-width: 0;
}

/* Own messages hug the right, so the group does too. */
.text-end > .hx-msg-line {
    justify-content: flex-end;
}

.hx-msg-tools {
    display: inline-flex;
    align-items: center;
    gap: .1rem;
    flex-shrink: 0;
}

.hx-msg-tools form {
    display: inline-flex;
}

/* Icons rather than words: four labels beside every message is more text than
   the messages. The accessible name lives on the button, because a control
   whose label is a picture still has to say what it does. */
.hx-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* 32px: comfortably past the 24px minimum for a touch target, without
       making four of them wider than the message they sit beside. */
    width: 2rem;
    height: 2rem;
    padding: 0;
    border: 0;
    border-radius: 999px;
    background: none;
    color: var(--bs-secondary-color);
    cursor: pointer;
    text-decoration: none;
    transition: color .12s ease-in-out, background-color .12s ease-in-out;
}

.hx-icon-btn:hover,
.hx-icon-btn:focus-visible {
    background: var(--hx-surface-muted);
    color: var(--bs-body-color);
}

.hx-icon-btn.is-danger:hover,
.hx-icon-btn.is-danger:focus-visible,
.hx-message-report:hover,
.hx-message-report:focus-visible {
    color: var(--bs-danger);
}

.hx-icon {
    display: block;
    pointer-events: none;   /* clicks belong to the button, not the path */
}

/* Time and the edited marker, quiet, on their own line under the message. */
.hx-msg-meta {
    display: flex;
    align-items: center;
    gap: .4rem;
    margin-top: .1rem;
    font-size: .72rem;
    line-height: 1.4;
    color: var(--bs-secondary-color);
}

.text-end > .hx-msg-meta {
    justify-content: flex-end;
}

/* Editing a message in place.
 *
 * Stands where the bubble was, so the thread does not jump and it is obvious
 * which message is being changed. Replaced window.prompt, which was a browser
 * dialog in the middle of a themed page, single-line for a message that may
 * not be, and silently inert in a browser set to suppress dialogs.
 */
.hx-edit-box {
    display: inline-block;
    width: min(100%, 26rem);
    text-align: left;
    margin: .1rem 0;
}

.hx-edit-field {
    resize: vertical;
    min-height: 2.6rem;
}

.hx-edit-buttons {
    display: flex;
    gap: .35rem;
    margin-top: .35rem;
}

.hx-edit-error {
    margin-top: .3rem;
    font-size: .78rem;
    color: var(--bs-danger);
}

/* "Seen", beside the time on your own messages. Quiet: it answers a question
   somebody had, rather than announcing itself. */
.hx-read {
    color: var(--bs-secondary-color);
}

/* Whether somebody is online. Quiet by default; the green is the only strong
   colour, and it is doing the work of a word so it also has one beside it. */
.hx-presence {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    font-size: .78rem;
    color: var(--bs-secondary-color);
}

.hx-presence-dot {
    width: .5rem;
    height: .5rem;
    border-radius: 50%;
    background: var(--bs-border-color);
    flex-shrink: 0;
}

.hx-presence.is-online {
    color: #2f9e44;
}

.hx-presence-dot.is-online,
.hx-presence.is-online .hx-presence-dot {
    background: #2f9e44;
}

/* The compact badge beside a name in a list. Small, so a row of them does not
   outweigh the names they belong to, but readable without a hover - a phone
   has none, and a bare dot there meant nothing. */
.hx-presence-inline {
    font-size: .7rem;
    margin-left: .35rem;
    white-space: nowrap;
    vertical-align: middle;
}
