/* ===================================================================
   The Bloc — Public landing page (Phase 2 #3)
   Stand-alone styles for `/` (unauth). Same visual language as the
   admin dashboard but scoped to .bloc-public so nothing leaks.
   =================================================================== */

* { box-sizing: border-box; }

.bloc-public {
    /* --text, --muted, --border, --border-strong, --halftone-dot,
       --accent-secondary and --accent-primary come from :root in tokens.css;
       only the per-scope values live here. */
    --surface: var(--ground);
    --card-fill: var(--surface-800);

    /* Spec §4.3 asks for a "centred column" and gives no width. Ruling D3
       (amended) settled it by capture rather than by taste, at 1440x900,
       candidates 640 / 760 / 880:

         640  BetterMC's connect address SPLITS - `word-break: break-all`
              renders `bmc.thebloc.party:2` / `5565`, severing the port
              mid-number (measured: 2 line boxes, 621.3px of text into 596px
              of content box). The one string a visitor has to read off the
              screen and type into Minecraft. Disqualified on that alone.
              Map aspect 1.100 - a near-square porthole.
         760  address fits on one line with 94.7px to spare; map 714x540,
              aspect 1.322 (~4:3), a normal shape for a world.  CHOSEN.
         880  also fits, but leaves 214.7px of dead width beside the widest
              element on a page whose BetterMC render is a hero and a footer,
              and at 1440 it is 280px of margin a side - not a column, just a
              slightly narrower page.

       One custom property, not two literals, because `.bp-header-inner` must
       track it exactly or the brand stops aligning with the card edge. */
    --bp-column: 760px;

    margin: 0;
    min-height: 100vh;
    background: var(--surface);
    background-size: 6px 6px;
    color: var(--text);
    font-family: 'Space Grotesk', system-ui, sans-serif;
    line-height: 1.45;
}

/* --- Header strip --- */

/* The strip stays full-bleed - it is the page's top edge, and a 760px-wide
   bar floating on the flat ground would read as a second card. What moves is its
   CONTENT: `.bp-header-inner` carries the same max-width and the same 22px
   side padding as `.bp-main`, so the brand mark starts on the same vertical as
   the hero card's left edge. Before this the mark sat hard against the
   viewport while the column was centred 340px away, which is the shape of a
   layout that was never a column. */
.bp-header {
    background: var(--card-fill);
    border-bottom: 1px solid var(--border);
    padding: 14px 0;
}
.bp-header-inner {
    max-width: var(--bp-column);
    margin: 0 auto;
    padding: 0 22px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
}
.bp-wordmark {
    display: block;
    height: 30px;
    width: auto;
}
.bp-auth {
    display: flex;
    align-items: center;
    gap: 12px;
    font-family: 'Overpass Mono', ui-monospace, monospace;
    font-size: 11px;
    letter-spacing: .14em;
    text-transform: uppercase;
}
/* Ink is `--accent-secondary` (bloc-300), not `--accent-primary` (bloc-500).
   tokens.css says it in as many words at the 500 step: "NOT a fill for anything
   carrying words", and it names 300 "accent text on dark, links". Measured on
   this page's real ground, bloc-500 as 11px ink is 3.84:1 against the header's
   surface-800 - under the 4.5:1 floor - and bloc-300 is 6.36:1, which is what
   the hero eyebrow and the map title were already using two cards down.

   The BORDER stays bloc-500 deliberately: a border is a graphic, its floor is
   3:1, and 3.84:1 clears it. Moving it too would lighten the whole control, and
   the failure was the ink. */
.bp-login,
.bp-dashboard-btn {
    color: var(--accent-secondary);
    text-decoration: none;
    padding: 7px 12px;
    border: 1px solid var(--accent-primary);
    border-radius: var(--radius-control);
    transition: background .12s, color .12s;
}
/* The hover ink is `--surface-950`, not `--surface`, and the difference is the
   whole reason this rule carries a comment.

   `--surface` in this scope is `--ground` (surface-900), and surface-900 on a
   bloc-500 fill measures 4.35:1 - just under the 4.5:1 floor for 11px ink. The
   resting ink above was just taken from 3.84:1 to 6.36:1, so leaving this
   would have made the control HARDER to read at the exact moment you aimed at
   it: the same defect this panel already fixed once for its primary buttons
   (CHANGELOG 2026-08-21), arriving by the back door of a hover state no
   resting-state contrast sweep ever visits.

   surface-950 is not a guess either - tokens.css measured it at the 500 step
   and wrote the number down: "the only ink that clears it is surface-950 at
   4.59:1". This is that ink. */
.bp-login:hover,
.bp-dashboard-btn:hover {
    background: var(--accent-primary);
    color: var(--surface-950);
}
.bp-user {
    color: var(--muted);
}
.bp-logout {
    color: var(--muted);
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    cursor: pointer;
    letter-spacing: .14em;
    text-transform: uppercase;
}
/* Same move, same reason: this is 11px ink in `.bp-auth`, so it carries the
   4.5:1 floor and bloc-500 was 3.84:1 against it. It is a HOVER ink, so it
   never showed up in a resting-state contrast sweep - which is exactly why the
   token rule is the thing to apply, not the list of rows that happened to fail. */
.bp-logout:hover { color: var(--accent-secondary); }

/* --- Main wrapper --- */

.bp-main {
    max-width: var(--bp-column);
    margin: 0 auto;
    padding: 36px 22px;
    display: flex;
    flex-direction: column;
    gap: 22px;
}

/* --- Hero --- */

/* Spec §3.3: cards are surface-800 on a surface-600 border at radius 14. The
   fill was already `--card-fill` (surface-800); what moves is the border, from
   `--border-strong` (surface-500) to `--border` (surface-600), so the hero and
   the map card stop drawing two different edges, and the corner, from square.
   18 is §3.3's padding and stays the horizontal value; the vertical is 2x it,
   because a hero that breathes at 18px top and bottom is a row, not a hero. */
.bp-hero {
    background: var(--card-fill);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
    padding: 36px 18px;
    text-align: center;
}
.bp-hero-eyebrow {
    font-family: 'Overpass Mono', ui-monospace, monospace;
    font-size: 11px;
    letter-spacing: .22em;
    text-transform: uppercase;
    color: var(--accent-secondary);
    margin-bottom: 10px;
}
.bp-hero-address {
    font-family: 'Overpass Mono', ui-monospace, monospace;
    font-size: clamp(28px, 5vw, 44px);
    font-weight: 700;
    color: var(--text);
    letter-spacing: -.01em;
    line-height: 1;
    word-break: break-all;
    background: transparent;
    border: 0;
    padding: 8px 4px;
    cursor: pointer;
    transition: color .12s;
}
/* This one KEEPS `--accent-primary` while the three 11px inks around it moved
   to `--accent-secondary`, and the difference is measured rather than stylistic.
   The address renders at clamp(28px, 5vw, 44px) at weight 700, which is large
   text: its floor is 3:1, and bloc-500 is 3.84:1 on this card. It clears its own
   floor, so there is nothing to fix, and the brighter step is what makes a
   44px display element light up when you point at it. */
.bp-hero-address:hover { color: var(--accent-primary); }
.bp-hero-copy-hint {
    margin-top: 6px;
    font-family: 'Overpass Mono', ui-monospace, monospace;
    font-size: 10px;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--muted);
}
/* Considered and deliberately left on the accent (ruled 2026-08-21). §3.8 would
   argue for `--success`, and the 10px ink is 3.84:1 - but this is not standing
   text: the inline script paints it for 2.5s after a click (home.html's
   `setTimeout(..., 2500)` - read, not assumed) and then restores
   "Click address to copy". A transient confirmation the user triggered, is
   looking at, and which reverts on its own is not the same object as a status
   line that sits there. Left as-is rather than silently omitted. */
.bp-hero-copy-hint.copied { color: var(--accent-primary); }
.bp-hero-status {
    margin-top: 22px;
    display: inline-flex;
    align-items: center;
    gap: 10px;
    padding: 8px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
    font-family: 'Overpass Mono', ui-monospace, monospace;
    font-size: 12px;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--text);
    white-space: nowrap;
}
.bp-hero-status-dot {
    width: 8px; height: 8px; border-radius: 50%;
    background: var(--muted);
}
/* Ruling D2. Online painted `--accent-primary` here, a decision from the
   orange era when the accent WAS the "good" colour; every other surface in the
   panel now says online = `--success` (the shell dot, the chips), and spec §3.8
   is explicit that colour carries state, never decoration. Two sites, because
   the dot and the word must never disagree.

   Offline deliberately does NOT follow the shell, which paints its offline dot
   `--surface-400`. The audiences differ: for an operator, offline is one state
   among many on a page full of controls; for a visitor it is the entire answer
   to "can I join right now", so it stays `--danger` and stays loud. Neither
   colour is the only signal - the word beside the dot says it too (§7). */
.bp-hero-status--online .bp-hero-status-dot { background: var(--success); }
/* The DOT keeps `--danger` and the WORD does not, and the split is the whole
   point. Measured on the card: danger-500 as 12px ink is 3.86:1, under the
   4.5:1 text floor; as a dot it is a graphic at a 3:1 floor and clears it. So
   the loud red stays exactly where D2 wanted it - the signal a visitor reads
   across the page - and the word takes `--danger-text` (danger-300, 7.83:1),
   which tokens.css declares for precisely this: "the light text shade of each
   family". Still the danger family, still not the shell's neutral. */
.bp-hero-status--offline .bp-hero-status-dot { background: var(--danger); }
.bp-hero-status--online { color: var(--success); }
.bp-hero-status--offline { color: var(--danger-text); }

/* --- Map card --- */

.bp-map {
    background: var(--card-fill);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
    overflow: hidden;  /* pre-existing, and now load-bearing: it is what clips
                          the iframe's square corners to the card's radius */
}
.bp-map-head {
    padding: 12px 18px;
    border-bottom: 1px solid var(--border);
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
}
.bp-map-title {
    font-family: 'Overpass Mono', ui-monospace, monospace;
    font-size: 11px;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--accent-secondary);
}
.bp-map-full {
    font-family: 'Overpass Mono', ui-monospace, monospace;
    font-size: 11px;
    letter-spacing: .14em;
    text-transform: uppercase;
    /* 11px ink, so the 4.5:1 floor: bloc-500 measured 3.84:1 on the card,
       bloc-300 is 6.36:1 - and it now matches `.bp-map-title` sitting on the
       same hairline, which was already `--accent-secondary`. */
    color: var(--accent-secondary);
    text-decoration: none;
}
/* 1.15, not the 1.2 this was. `filter: brightness(1.15)` is the panel's one
   hover for a coloured text link - dashboard.css writes it for
   `.bloc-text-link` and `.bloc-activity-foot` - and a third value for the same
   gesture is how a vocabulary stops being one. */
.bp-map-full:hover { filter: brightness(1.15); }
.bp-map iframe {
    display: block;
    width: 100%;
    height: 540px;
    border: 0;
}
@media (max-width: 768px) {
    .bp-map iframe { height: 380px; }
}

/* --- Footer --- */

.bp-foot {
    border-top: 1px solid var(--border);
    padding: 18px 22px;
    text-align: center;
    font-family: 'Overpass Mono', ui-monospace, monospace;
    font-size: 10px;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--muted);
}
