/* Hub CSS - Member Dashboard */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;700&family=Lato:wght@400;700;900&display=swap');

/* ── Global responsive-image reset ──────────────────────────────────────
   Any <img> without a scoped size rule falls back to its native/attribute
   size and can overflow a narrow viewport (guild logo SVGs in particular
   ship with only a viewBox, no width/height, so an unscoped <img> renders
   at the browser's 300x150 replaced-element default). Existing sized rules
   (.pl-guild-hero__img, .pl-guild-gallery__item img, .cp-detail__hero-logo
   img, etc.) all win by specificity — class selectors beat this bare
   element selector — so nothing below needs to change. */
img {
    max-width: 100%;
    height: auto;
}

[x-cloak] { display: none !important; }

/* Shared tab strip — one row, horizontally scrollable on phones instead of
   wrapping to a second line. Used by guild pages, settings, and voting.

   Ruling 24: the strip scrolls, and now it says so. The merged per-class strip is seven
   tabs (eight with the instructor discount-codes flag on), and at 390px the last three sit
   off-screen — with the scrollbar hidden, nothing on the page suggested they were there.
   The right-edge fade appears only when there IS more to the right, with no script and no
   extra markup: two background layers, a "fade" pinned to the element
   (background-attachment: scroll) and an opaque "cover" the same size pinned to the
   *content* (background-attachment: local). The cover sits at the content's right edge, so
   while there is more to scroll it is off-screen, and the moment you reach the end it
   slides over the fade and hides it. A strip that does not overflow has its content edge at
   its element edge, so the cover covers the fade from the start and nothing is ever drawn.

   The cover has to paint whatever the strip sits on — the page ground on most pages, a card
   on voting and wiki review — so it reads --pl-tabs-bg rather than a colour, and both
   values are theme tokens, so it works in Obsidian and Slate alike (FRONTEND.md rule 7).
   Give --pl-tabs-bg a new value on any future container with its own background.

   This is a SHARED component — guilds, settings, voting, the wiki, equipment manage and now
   the per-class screen all render it — so this has site-wide reach. */
.pl-tabs {
    --pl-tabs-bg: var(--hub-bg);
    display: flex;
    gap: 0;
    border-bottom: 1px solid var(--hub-border);
    margin-bottom: 1.25rem;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    background-image:
        linear-gradient(to left, var(--pl-tabs-bg), var(--pl-tabs-bg)),
        linear-gradient(to left, var(--pl-tabs-bg), transparent);
    background-position: right center, right center;
    background-repeat: no-repeat;
    background-size: 2.5rem 100%, 2.5rem 100%;
    background-attachment: local, scroll;
}
.hub-card .pl-tabs { --pl-tabs-bg: var(--hub-card-bg); }
.pl-tabs::-webkit-scrollbar { display: none; }
.pl-tabs .vote-tab { flex: 0 0 auto; white-space: nowrap; }

/* Tab nav used in the voting standings card */
.vote-tab {
    padding: 0.625rem 1.25rem;
    font-size: 0.9rem;
    color: var(--hub-text-muted);
    background: transparent;
    border: none;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease;
}
.vote-tab:hover { color: var(--hub-text); }
.vote-tab--active { color: var(--hub-link); border-bottom-color: var(--hub-link); }

/* ========================================
   HTMX Loading Indicator
   ======================================== */
.htmx-request .hub-content {
    opacity: 0.6;
    transition: opacity 200ms ease-out;
}

/* ========================================
   CSS Custom Properties - Dark (default)
   ======================================== */
:root {
    /* Surfaces — "Obsidian" elevation ladder (near-black charcoal).
       Distinct layers replace the old single flat navy so the UI reads
       as depth, not one monotone wash. Anchored on PL blue #092e4b. */
    --hub-bg: #0a0b10;            /* deepest page background */
    --hub-surface: #13151d;       /* inset panels, tiles, table stripes */
    --hub-card-bg: #181b24;       /* cards & modals (sits above the page) */
    --hub-elevated: #20242f;      /* dropdowns, popovers, raised pills */
    --hub-card-border: rgba(255, 255, 255, 0.07);
    --hub-border: rgba(255, 255, 255, 0.08);
    --hub-border-strong: rgba(255, 255, 255, 0.14);
    --hub-text: #F4EFDD;
    --hub-text-muted: #8b97a8;
    --hub-topbar-bg: #0d0f15;
    --hub-topbar-border: rgba(255,255,255,0.06);
    --hub-dropdown-bg: #20242f;
    --hub-dropdown-border: rgba(255,255,255,0.10);
    --hub-input-bg: #14161f;
    --hub-input-border: rgba(255,255,255,0.14);

    /* Sidebar — theme-aware (was hardcoded to --color-navy, which never
       switched on light mode). These tokens are overridden under [data-theme]. */
    --hub-sidebar-bg: #0d0f15;
    --hub-sidebar-text: #F4EFDD;
    --hub-sidebar-muted: rgba(244, 239, 221, 0.60);
    /* A "Coming soon" nav entry (#405). Deliberately the SAME cream as a live entry, just
       quieter — a de-emphasis on the sidebar's own scale, not a swap to the page text scale.
       --hub-text-muted is a different hue here and byte-identical to --hub-sidebar-muted in
       light mode, which made a Coming soon entry pixel-identical to a live one at rest.
       6.40:1 live vs 3.47:1 here: visibly quieter, still above the 3:1 UI floor. */
    --hub-sidebar-soon: rgba(244, 239, 221, 0.40);
    --hub-sidebar-hover: rgba(255, 255, 255, 0.06);
    --hub-sidebar-border: rgba(255, 255, 255, 0.08);

    --color-navy: #092E4C;        /* brand structural blue (button text, overlays) */
    /* Brighter PL-blue sibling for interactive/structural accents on dark */
    --hub-blue: #3d8bd4;
    --hub-blue-soft: rgba(61, 139, 212, 0.15);
    /* Hero gradient: PL blue #092e4b fading to near-black ("black & blue") */
    --hub-hero-from: #15527f;
    --hub-hero-mid: #092e4b;
    --hub-hero-to: #0a0d14;

    --color-tuscan-yellow: #EEB44B;
    --color-yellow-hover: #d4a043;
    /* Gold as TEXT (links, active tabs, prices). Theme-aware so it stays
       bright on dark but darkens to a readable amber on light surfaces.
       Gold FILLS (buttons, pills, bars) keep --color-tuscan-yellow. */
    --hub-link: #EEB44B;
    --hub-link-hover: #d4a043;
    --color-cream: #F4EFDD;
    --color-brand-link: #3d8bd4;
    --color-error: #f0a0a0;
    --color-error-bg: rgba(240, 160, 160, 0.12);
    --color-success: #7bc88f;
    --color-success-bg: rgba(123, 200, 143, 0.12);

    /* Class lifecycle badge / review pipeline / readiness marks (class-lifecycle spec
       PR 1). Text-on-surface tones: bright on Obsidian here, darkened to readable
       amber / green / red on Slate (overridden below). */
    --pl-lifecycle-review: var(--color-tuscan-yellow);
    --pl-lifecycle-live: var(--color-success);
    --pl-lifecycle-cancelled: var(--color-error);
    --pl-lifecycle-live-contrast: var(--color-navy);
    /* The guild's share of the money split (Host a Workshop): the live green with
       navy text on Obsidian; the light block flips the text to cream over its
       darker green. Gold / blue / green, one triad in both themes. */
    --pl-split-guild-bg: var(--pl-lifecycle-live);
    --pl-split-guild-fg: var(--color-navy);

    /* Google Calendar sync-state badge (Screen C) — theme tokens so the badge
       stays legible on both Obsidian (here) and Slate (overridden below). */
    --pl-sync-synced: #6ee7b7;
    --pl-sync-pending: #8b97a8;
    --pl-sync-failed: #f0a0a0;

    /* Help-center audience badges — the Admins violet and Developers magenta
       (member/instructor/lead reuse --hub-blue / --pl-sync-synced / the gold
       family). Theme pairs overridden below. */
    --pl-help-admin: #c4a3f5;
    --pl-help-developer: #ef9fce;

    --font-heading: 'Lato', system-ui, -apple-system, sans-serif;
    --font-body: 'Inter', system-ui, -apple-system, sans-serif;

    --sidebar-width: 220px;
    --topbar-height: 56px;
}

/* ========================================
   Light Theme Override
   ======================================== */
[data-theme="light"] {
    /* "Slate" light — cool neutral gray (not warm cream) with white cards. */
    --hub-bg: #eef0f3;
    --hub-surface: #e6e9ee;
    --hub-card-bg: #ffffff;
    --hub-elevated: #ffffff;
    --hub-card-border: #dfe3ea;
    --hub-border: #e2e6ec;
    --hub-border-strong: #cfd5de;
    --hub-text: #1D1E1E;
    --hub-text-muted: #5b6675;
    --hub-topbar-bg: #ffffff;
    --hub-topbar-border: #e2e6ec;
    --hub-dropdown-bg: #ffffff;
    --hub-dropdown-border: #e2e6ec;
    --hub-input-bg: #f4f6f8;
    --hub-input-border: #d3d9e1;

    /* Sidebar follows the theme (the fix) — light rail in light mode. */
    --hub-sidebar-bg: #ffffff;
    --hub-sidebar-text: #1D1E1E;
    --hub-sidebar-muted: #5b6675;
    /* Same de-emphasis on the light rail: 5.83:1 live vs 3.50:1 here. */
    --hub-sidebar-soon: #7f8a9a;
    --hub-sidebar-hover: rgba(9, 46, 75, 0.06);
    --hub-sidebar-border: #e2e6ec;

    --hub-blue: #2f6fb0;
    --hub-blue-soft: rgba(9, 46, 75, 0.08);
    --pl-lifecycle-review: #9a6a00;
    --pl-lifecycle-live: #1f7a52;
    --pl-lifecycle-cancelled: #b03030;
    --pl-lifecycle-live-contrast: #ffffff;
    --pl-split-guild-fg: var(--color-cream);
    --hub-hero-from: #f8fafc;
    --hub-hero-mid: #f1f5f9;
    --hub-hero-to: #e2e8f0;

    /* Darker amber for gold text on white (~5:1 contrast, passes AA). */
    --hub-link: #9c5e0d;
    --hub-link-hover: #7e4b09;

    /* Sync badge — darker greens/reds that pass contrast on white cards. */
    --pl-sync-synced: #1f7a52;
    --pl-sync-pending: #5b6675;
    --pl-sync-failed: #b03030;

    /* Help audience badges — darker violet/magenta that pass contrast on white cards. */
    --pl-help-admin: #6d3fc0;
    --pl-help-developer: #a83a85;
}

/* ========================================
   Reset & Base
   ======================================== */
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

html { scroll-behavior: smooth; overflow-x: hidden; }

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        transition-duration: 0.01ms !important;
    }
}

body {
    font-family: var(--font-body);
    font-weight: 300;
    line-height: 1.6;
    background-color: var(--hub-bg);
    color: var(--hub-text);
    min-height: 100vh;
    display: flex;
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
    font-family: var(--font-heading);
    font-weight: 700;
    line-height: 1.2;
    color: var(--hub-text);
}

a {
    color: var(--hub-link);
    text-decoration: none;
    transition: color 0.15s ease;
}

a:hover { color: var(--hub-link-hover); }

/* ========================================
   Sidebar
   ======================================== */
.hub-sidebar {
    position: fixed;
    top: 0;
    left: 0;
    width: var(--sidebar-width);
    height: 100vh;
    height: 100dvh; /* dynamic viewport height — survives mobile URL-bar collapse */
    background-color: var(--hub-sidebar-bg);
    border-right: 1px solid var(--hub-sidebar-border);
    display: flex;
    flex-direction: column;
    z-index: 100;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    transition: transform 0.2s ease;
    padding-top: env(safe-area-inset-top, 0px);
    padding-bottom: env(safe-area-inset-bottom, 0px);
}

.hub-sidebar--closed {
    transform: translateX(-100%);
}

/* Shared brand block — identical in hub and admin */
.pl-brand {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    padding: 1.25rem 1rem;
    color: var(--hub-sidebar-text);
    border-bottom: 1px solid var(--hub-sidebar-border);
    text-decoration: none;
}

.pl-brand:hover { color: var(--hub-sidebar-text); }

.pl-brand__icon { width: 24px; height: 24px; }

.pl-brand__info {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}

.pl-brand__text {
    font-family: var(--font-heading);
    font-size: 1.125rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    line-height: 1.2;
}

.pl-brand__label {
    font-size: 0.625rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    padding: 0.125rem 0.375rem;
    border-radius: 10px;
    background-color: rgba(238, 180, 75, 0.15);
    color: var(--color-tuscan-yellow);
    width: fit-content;
}

.hub-sidebar__nav {
    padding: 0.75rem 0.5rem;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.hub-sidebar__divider {
    border: 0;
    border-top: 1px solid var(--hub-sidebar-border);
    margin: 0.5rem 0.75rem;
    width: auto;
}

.hub-sidebar__link {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    padding: 0.5rem 0.75rem;
    font-size: 0.875rem;
    font-weight: 400;
    color: var(--hub-sidebar-muted);
    border-radius: 6px;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.hub-sidebar__link:hover {
    background-color: var(--hub-sidebar-hover);
    color: var(--hub-sidebar-text);
}

.hub-sidebar__link.active {
    background-color: rgba(238, 180, 75, 0.12);
    color: var(--hub-sidebar-text);
    box-shadow: inset 3px 0 0 var(--color-tuscan-yellow);
    font-weight: 600;
}

.hub-sidebar__link.active svg {
    color: var(--color-tuscan-yellow);
}

/* "Coming soon" nav entry (#405): present but not yet. It must read as a feature that is on
   its way, never as a broken or failed link — so it keeps the icon, the label and the exact
   position it will occupy when it goes live, and gives up only the affordances of a link.
   No hover background and no pointer cursor, because both promise a navigation that is not
   coming. It is a <span> with .pl-help, so the bubble's hover/focus reveal is inherited
   wholesale from that component and nothing here re-implements it. */
/* Two classes, not one, and deliberately so: .pl-help is defined LATER in this file and sets
   `display: inline-flex; justify-content: center` for a 1.1rem "?" icon. At equal specificity
   it would win and centre the whole nav row. Qualifying with .pl-help outranks it and restores
   the sidebar row's own left-aligned layout. (This shipped wrong once; the screenshot caught
   an entry floating in the middle of the sidebar.) */
.hub-sidebar__link--soon.pl-help {
    color: var(--hub-sidebar-soon);
    cursor: default;
    display: flex;
    justify-content: flex-start;
    align-items: center;
}

.hub-sidebar__link--soon.pl-help:hover {
    background-color: transparent;
    color: var(--hub-sidebar-soon);
}

/* The icon rides the text colour. Every nav icon is stroke="currentColor", so this is
   inherited rather than set — but .hub-sidebar__link.active svg overrides colour for the
   active entry, which proves the icon is reachable by a rule, so pin the intent here. */
.hub-sidebar__link--soon.pl-help svg {
    color: inherit;
}

/* The bubble is anchored to a full-width row here rather than a 1.1rem "?" icon, so it hangs
   under the entry it belongs to instead of the row's centre. */
.hub-sidebar__link--soon .pl-help__bubble {
    left: 0.75rem;
    max-width: 240px;
}

.hub-sidebar__section-header {
    padding: 1.25rem 0.75rem 0.375rem;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--hub-sidebar-muted);
}

.hub-sidebar__section-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding: 1.25rem 0.75rem 0.375rem;
    font-family: var(--font-body);
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--hub-sidebar-muted);
    background: none;
    border: none;
    cursor: pointer;
    transition: color 0.15s ease;
}

.hub-sidebar__section-toggle:hover {
    color: var(--hub-sidebar-text);
}

/* "Coming soon" section heading (#405, the Guilds block). Same de-emphasis as
   .hub-sidebar__link--soon and the SAME --hub-sidebar-soon token, deliberately — a second
   muted colour would mean two answers to one question. Qualified with .pl-help for the same
   reason the link variant is: .pl-help is defined later in this file and would otherwise win
   on display and justify-content and centre the heading. */
.hub-sidebar__section-toggle--soon.pl-help {
    color: var(--hub-sidebar-soon);
    cursor: default;
    display: flex;
    justify-content: flex-start;
    align-items: center;
}

.hub-sidebar__section-toggle--soon.pl-help:hover {
    color: var(--hub-sidebar-soon);
}

.hub-sidebar__section-toggle--soon .pl-help__bubble {
    /* Anchored under the heading rather than centred on it, matching the link variant. */
    left: 0.75rem;
    max-width: 240px;
    /* The heading is uppercased and letter-spaced; .pl-help__bubble already resets both, but
       it inherits text-align from this flex parent, so pin it back to prose. */
    text-align: left;
}

.hub-sidebar__chevron {
    transition: transform 0.25s ease;
}

.hub-sidebar__section-toggle[aria-expanded="true"] .hub-sidebar__chevron {
    transform: rotate(180deg);
}

.hub-sidebar__collapsible {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 0.25s ease;
}

.hub-sidebar__collapsible.open {
    grid-template-rows: 1fr;
}

.hub-sidebar__collapsible-inner {
    overflow: hidden;
}

/* Sidebar footer — pinned to bottom, reuses .hub-sidebar__link styling */
.hub-sidebar__footer {
    margin-top: auto;
    padding: 0.75rem 0.5rem 1rem;
    border-top: 1px solid var(--hub-sidebar-border);
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.hub-sidebar__footer-label {
    font-size: 0.65rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--hub-sidebar-muted);
    padding: 0.35rem 0.75rem 0.25rem;
}

.hub-sidebar__ext-icon {
    margin-left: auto;
    opacity: 0.45;
    flex-shrink: 0;
}

.hub-sidebar__link--external:hover .hub-sidebar__ext-icon {
    opacity: 0.85;
}

.hub-sidebar__link--feedback {
    margin-top: 0.4rem;
    border-top: 1px dashed var(--hub-sidebar-border);
    padding-top: 0.75rem;
}

/* Email list used on the User Settings > Emails tab */
.hub-email-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 0.4rem; }
.hub-email-list__item label {
    display: flex; align-items: center; gap: 0.6rem;
    padding: 0.6rem 0.75rem;
    border: 1px solid var(--hub-border);
    border-radius: 6px;
    cursor: pointer;
}
.hub-email-list__item label:hover { background-color: rgba(255, 255, 255, 0.03); }
.hub-email-list__addr { flex: 1; font-family: var(--font-body); }

.hub-pill {
    display: inline-block;
    font-size: 0.7rem;
    font-weight: 600;
    padding: 0.15rem 0.5rem;
    border-radius: 10px;
    letter-spacing: 0.02em;
}
.hub-pill--ok { background: rgba(52, 211, 153, 0.15); color: #6ee7b7; }
.hub-pill--warn { background: rgba(251, 191, 36, 0.15); color: #fbbf24; }
.hub-pill--primary { background: rgba(238, 180, 75, 0.15); color: var(--color-tuscan-yellow, #EEB44B); }
/* Invite-status pills (introduced by the Manage Members invites panel). Same shape as
   the family above; new in-family modifiers, no new prefix/token. */
.hub-pill--neutral { background: rgba(139, 151, 168, 0.18); color: var(--hub-text-muted); }
.hub-pill--danger { background: rgba(224, 85, 85, 0.16); color: #f0a0a0; }

/* ========================================
   Google Calendar sync-state badge (Screen C / E)
   Shown per event row when Google sync is on. Colors come from theme tokens
   defined for both :root (Obsidian) and [data-theme="light"] (Slate) above —
   no hardcoded hex here, so the badge tracks the theme in both directions.
   ======================================== */
.pl-sync-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    font-size: 0.75rem;
    font-weight: 600;
}
.pl-sync-badge--synced { color: var(--pl-sync-synced); }
.pl-sync-badge--pending { color: var(--pl-sync-pending); }
.pl-sync-badge--failed { color: var(--pl-sync-failed); }

/* Compact "synced to the shared Google Calendar" flag — a small green calendar-check
   glyph that replaces the wordy pill wherever a synced event is listed. */
.pl-sync-flag {
    display: inline-flex;
    align-items: center;
    color: var(--pl-sync-synced);
    line-height: 1;
}
.pl-sync-flag svg { display: block; }
/* The failure/config-gap reason, on its own line beneath the badge — visible
   inline text, never a title-tooltip (dead on touch, FRONTEND Screen C). */
.pl-sync-badge__reason {
    display: block;
    margin-top: 0.2rem;
    font-size: 0.75rem;
    color: var(--hub-text-muted);
}

/* ========================================
   Invites panel — Manage Members page
   #invites-list is the HTMX-swappable region.
   ======================================== */
.pl-invite-card__header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-bottom: 1rem;
}
.pl-invite-card__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}
.pl-invite-form {
    margin-bottom: 1.25rem;
}
.pl-invite-form__actions {
    display: flex;
    gap: 0.5rem;
    margin-top: 0.75rem;
}
.pl-invite-hint {
    margin: 0.75rem 0 0;
    font-size: 0.8125rem;
    color: var(--hub-text-muted);
    line-height: 1.5;
}
.pl-invite-expired {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin-top: 0.25rem;
}
.pl-invite-expired__bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}
.pl-invite-expired__list {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
.pl-invite-list {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
.pl-invite-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 0.75rem;
    padding: 0.75rem 0.85rem;
    border: 1px solid var(--hub-input-border);
    border-radius: 8px;
    background: var(--hub-surface);
}
.pl-invite-row__main {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    flex: 1 1 240px;
    min-width: 0;
}
.pl-invite-row__email {
    font-weight: 500;
    color: var(--hub-text);
    word-break: break-word;
}
.pl-invite-row__meta {
    font-size: 0.8125rem;
    color: var(--hub-text-muted);
}
.pl-invite-row__actions {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
}
.pl-invite-empty {
    color: var(--hub-text-muted);
    font-size: 0.875rem;
    margin: 0;
    padding: 0.5rem 0;
}
/* Light theme (Slate) contrast bumps — SCOPED to the invite list so the shared
   .hub-pill--ok used on other pages (e.g. user_settings.html) is untouched. */
[data-theme="light"] .pl-invite-list .hub-pill--ok { color: #1f7a52; }
[data-theme="light"] .pl-invite-list .hub-pill--neutral { color: #5b6675; }
[data-theme="light"] .pl-invite-list .hub-pill--danger { color: #b03030; }
/* Same contrast bumps for the person-status badges in the Manage Members table
   ("Hasn't signed in yet" / "Non-member user"), Review fix #8. */
[data-theme="light"] .pl-members-table .hub-pill--neutral { color: #5b6675; }
[data-theme="light"] .pl-members-table .hub-pill--danger { color: #b03030; }
/* "Your proposed events" status pills (Community Calendar Events tab + propose page):
   the shared amber/red pills need a darker text on the light theme to stay readable. */
[data-theme="light"] .pl-proposals .hub-pill--warn { color: #9a6a00; }
[data-theme="light"] .pl-proposals .hub-pill--danger { color: #b03030; }

/* ========================================
   Automations dashboard (Site Settings → Automations)
   A card list of scheduled jobs: grid on desktop, stacked with per-region labels on mobile.
   Status is shown with the shared .hub-pill--* family (no new colored pill classes); only
   layout is new here. Colors come from theme tokens — verified in Obsidian + Slate.
   ======================================== */
.pl-automation-callout {
    margin: 0;
    padding: 0.75rem 1rem;
    border: 1px solid var(--hub-card-border);
    border-left: 3px solid var(--color-tuscan-yellow);
    border-radius: 6px;
    background: var(--hub-card-bg);
    color: var(--hub-text-muted);
    font-size: 0.875rem;
    line-height: 1.5;
}
.pl-automation-callout a { color: var(--color-tuscan-yellow); font-weight: 600; }

.pl-automation-list { display: flex; flex-direction: column; gap: 0.75rem; }
.pl-automation-card {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto auto auto;
    align-items: center;
    gap: 1rem;
    padding: 1rem;
    border: 1px solid var(--hub-card-border);
    border-radius: 8px;
    background: var(--hub-card-bg);
}
.pl-automation-card--paused { opacity: 0.62; }

.pl-automation-main { min-width: 0; }
.pl-automation-name {
    font-weight: 700;
    color: var(--hub-text);
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
}
.pl-automation-desc { color: var(--hub-text-muted); font-size: 0.85rem; margin-top: 0.15rem; }
.pl-automation-badge {
    font-size: 0.65rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    padding: 0.1rem 0.4rem;
    border-radius: 4px;
    background: rgba(224, 85, 85, 0.16);
    color: #f0a0a0;
}
.pl-automation-paused { color: var(--hub-text-muted); font-size: 0.8rem; font-style: italic; margin-top: 0.35rem; }

.pl-automation-cell { display: flex; flex-direction: column; gap: 0.3rem; align-items: flex-start; }
.pl-automation-cell-label {
    display: none; /* revealed only in the stacked mobile layout */
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--hub-text-muted);
}
.pl-automation-schedule { color: var(--hub-text); font-size: 0.85rem; white-space: nowrap; }
.pl-automation-lastrun { display: flex; flex-direction: column; gap: 0.2rem; }
.pl-automation-time { color: var(--hub-text-muted); font-size: 0.78rem; }
.pl-automation-error {
    color: #f0a0a0;
    font-size: 0.75rem;
    max-width: 220px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.pl-automation-run { align-items: flex-end; }

/* Legacy-CMS clarity sub-block spans the full card width below the five regions. */
.pl-automation-subblock {
    grid-column: 1 / -1;
    margin-top: 0.5rem;
    padding-top: 0.85rem;
    border-top: 1px dashed var(--hub-card-border);
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    align-items: flex-start;
}
.pl-automation-subnote { margin: 0; color: var(--hub-text-muted); font-size: 0.82rem; }
.pl-automation-subnote--off { color: #f0a0a0; font-weight: 600; }
.pl-automation-subblock code { font-size: 0.8rem; }

/* Light-mode (Slate) legibility for the shared pills used inside the cards — mirrors the
   scoped overrides added for the invite list / members table above. */
[data-theme="light"] .pl-automation-card .hub-pill--ok { color: #1f7a52; }
[data-theme="light"] .pl-automation-card .hub-pill--neutral { color: #5b6675; }
[data-theme="light"] .pl-automation-card .hub-pill--danger { color: #b03030; }
[data-theme="light"] .pl-automation-card .hub-pill--warn { color: #9a6a00; }
[data-theme="light"] .pl-automation-card .pl-automation-error,
[data-theme="light"] .pl-automation-subnote--off { color: #b03030; }
[data-theme="light"] .pl-automation-badge { background: rgba(224, 85, 85, 0.12); color: #b03030; }

@media (max-width: 640px) {
    .pl-automation-card {
        grid-template-columns: 1fr;
        align-items: stretch;
        gap: 0.75rem;
    }
    .pl-automation-cell-label { display: block; }
    .pl-automation-run { align-items: stretch; margin-top: 0.75rem; }
    .pl-automation-run .hub-btn { width: 100%; text-align: center; }
    .pl-automation-error { max-width: 100%; white-space: normal; }
}

/* Emails tab (Site Settings → Emails): the read-and-route email catalogue. Mirrors the
   Automations card set — a stacked list of cards, one per email the app can send. */
.pl-email-tab { display: flex; flex-direction: column; gap: 1.75rem; }
.pl-email-intro { margin: 0; color: var(--hub-text-muted); font-size: 0.875rem; max-width: 70ch; }
.pl-email-group { display: flex; flex-direction: column; gap: 0.75rem; }
.pl-email-group__title {
    margin: 0;
    font-size: 0.8125rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--hub-text-muted);
}
.pl-email-row {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    padding: 1rem 1.25rem;
    border: 1px solid var(--hub-card-border);
    border-radius: 8px;
    background: var(--hub-card-bg);
}
.pl-email-row__head { display: flex; align-items: baseline; gap: 0.6rem; flex-wrap: wrap; }
.pl-email-row__name { font-weight: 650; color: var(--hub-text); }
.pl-email-row__desc { color: var(--hub-text-muted); font-size: 0.875rem; }
.pl-email-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 1.25rem;
    font-size: 0.8125rem;
    color: var(--hub-text-muted);
}
.pl-email-meta strong { color: var(--hub-text); font-weight: 600; }
.pl-email-chans { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; }
.pl-email-chan {
    font-size: 0.6875rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--hub-text-muted);
    border: 1px solid var(--hub-card-border);
    border-radius: 999px;
    padding: 2px 9px;
}
.pl-email-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.15rem; }

/* Branded email preview shown in the Emails-tab modal. The iframe renders a full email
   document (its own light/dark shell), so it sits on a neutral canvas with internal scroll. */
.pl-email-preview { display: flex; flex-direction: column; gap: 0.75rem; }
.pl-email-preview__subject {
    margin: 0;
    font-size: 0.9rem;
    color: var(--hub-text);
    padding: 0.5rem 0.7rem;
    background: var(--hub-surface);
    border: 1px solid var(--hub-card-border);
    border-radius: 7px;
}
.pl-email-preview__subject span {
    font-size: 0.65rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--hub-text-muted);
    margin-right: 0.4rem;
}
.pl-email-preview__frame {
    width: 100%;
    height: 60vh;
    min-height: 360px;
    border: 1px solid var(--hub-card-border);
    border-radius: 7px;
    background: #eef0f3;
}
.pl-email-preview__empty { color: var(--hub-text-muted); font-size: 0.85rem; font-style: italic; margin: 0; }
@media (max-width: 640px) {
    .pl-invite-row__actions {
        width: 100%;
    }
    .pl-invite-row__actions .hub-btn {
        flex: 1 1 auto;
        text-align: center;
    }
}

/* ========================================
   Main Wrapper
   ======================================== */
.hub-main-wrapper {
    margin-left: var(--sidebar-width);
    flex: 1;
    /* min-width: 0 lets the wrapper shrink below its content's min-content
       width (flex items default to min-width: auto) — without it a wide
       grid track forces a page-level horizontal scroll on small phones. */
    min-width: 0;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    transition: margin-left 0.2s ease;
}

.hub-main-wrapper--expanded {
    margin-left: 0;
}

/* ========================================
   Shared Top Bar (.pl-topbar)
   ======================================== */
.pl-topbar {
    position: sticky;
    top: 0;
    z-index: 50;
    /* Grow by the status-bar/notch inset — the app webview is edge-to-edge
       (viewport-fit=cover + Capacitor contentInset "never"), so the bar
       itself must keep its controls below the system UI. */
    height: calc(var(--topbar-height) + env(safe-area-inset-top, 0px));
    background-color: var(--hub-topbar-bg);
    border-bottom: 1px solid var(--hub-topbar-border);
    display: flex;
    align-items: center;
    padding: env(safe-area-inset-top, 0px) 1.5rem 0;
    gap: 0.75rem;
    overflow: visible;
    min-width: 0;
}

.pl-topbar__toggle {
    background: none;
    border: none;
    color: var(--hub-text-muted);
    cursor: pointer;
    padding: 0.25rem;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 4px;
    transition: color 0.15s ease, background-color 0.15s ease;
}

.pl-topbar__toggle:hover {
    color: var(--hub-text);
    background-color: rgba(255, 255, 255, 0.06);
}

.pl-topbar__divider {
    width: 1px;
    height: 20px;
    background-color: var(--hub-topbar-border);
}

.pl-badge--version {
    display: inline-flex;
    align-items: center;
    align-self: flex-start;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.03em;
    color: var(--color-tuscan-yellow);
    background-color: rgba(238, 180, 75, 0.15);
    padding: 0.125rem 0.5rem;
    border-radius: 999px;
    border: none;
    cursor: pointer;
    font-family: var(--font-body);
    transition: background-color 0.15s ease, color 0.15s ease;
}

.pl-badge--version:hover {
    background-color: rgba(238, 180, 75, 0.28);
}

/* View switcher — distinct button to switch between admin/hub */
.pl-view-switcher {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.25rem 0.75rem;
    font-family: var(--font-body);
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--color-tuscan-yellow);
    background-color: rgba(238, 180, 75, 0.1);
    border: 1px solid rgba(238, 180, 75, 0.25);
    border-radius: 6px;
    text-decoration: none;
    transition: background-color 0.15s ease, border-color 0.15s ease;
    white-space: nowrap;
}

.pl-view-switcher:hover {
    background-color: rgba(238, 180, 75, 0.18);
    border-color: rgba(238, 180, 75, 0.4);
    color: var(--color-tuscan-yellow);
}

.pl-view-switcher svg {
    flex-shrink: 0;
}

.pl-topbar__spacer { flex: 1; }

.pl-topbar__theme-toggle {
    background: none;
    border: none;
    color: var(--hub-text-muted);
    cursor: pointer;
    padding: 0.375rem;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 6px;
    transition: color 0.15s ease, background-color 0.15s ease;
}

.pl-topbar__theme-toggle:hover {
    color: var(--hub-text);
    background-color: rgba(255, 255, 255, 0.06);
}

[data-theme="light"] .pl-topbar__theme-toggle:hover {
    background-color: rgba(0, 0, 0, 0.06);
}

/* ========================================
   Shared Profile Dropdown (.pl-profile)
   ======================================== */
.pl-profile {
    position: relative;
    z-index: 100;
}

.pl-profile__avatar {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background-color: var(--color-tuscan-yellow);
    color: var(--color-navy);
    font-size: 0.8125rem;
    font-weight: 700;
    font-family: var(--font-body);
    border: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: box-shadow 0.15s ease;
}

.pl-profile__avatar:hover {
    box-shadow: 0 0 0 2px var(--hub-topbar-bg), 0 0 0 4px var(--color-tuscan-yellow);
}

.pl-profile__dropdown {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    width: 240px;
    background-color: var(--hub-dropdown-bg);
    border: 1px solid var(--hub-dropdown-border);
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.3);
    overflow: hidden;
    z-index: 100;
}

.pl-profile__dropdown-header {
    padding: 0.875rem 1rem;
    border-bottom: 1px solid var(--hub-dropdown-border);
}

.pl-profile__dropdown-name {
    font-size: 0.875rem;
    font-weight: 700;
    color: var(--hub-text);
}

.pl-profile__dropdown-email {
    font-size: 0.75rem;
    color: var(--hub-text-muted);
    margin-top: 2px;
}

.pl-profile__dropdown-item {
    display: block;
    width: 100%;
    padding: 0.625rem 1rem;
    font-size: 0.875rem;
    font-family: var(--font-body);
    color: var(--hub-text);
    background: none;
    border: none;
    cursor: pointer;
    text-align: left;
    transition: background-color 0.15s ease;
    text-decoration: none;
}

.pl-profile__dropdown-item:hover {
    background-color: rgba(255,255,255,0.05);
    color: var(--hub-text);
}

[data-theme="light"] .pl-profile__dropdown-item:hover {
    background-color: rgba(0,0,0,0.04);
}

.pl-profile__dropdown-item--danger { color: #e05555; }
.pl-profile__dropdown-item--danger:hover { color: #e05555; }

.pl-profile__dropdown-divider {
    height: 1px;
    background-color: var(--hub-dropdown-border);
    margin: 0.25rem 0;
}

.pl-profile__dropdown-mobile-item { display: none; }
.pl-view-switcher__label { white-space: nowrap; }
@media (max-width: 768px) {
    .pl-topbar__theme-toggle, .pl-view-switcher__label { display: none; }
    .pl-view-switcher { padding: 0.375rem; gap: 0; }
    .pl-profile__dropdown-mobile-item { display: block; }
}

/* ========================================
   Content Area
   ======================================== */

/* Skip link: the first focusable element on every hub page (hub/base.html), so a
   keyboard or screen-reader user can jump past the sidebar and topbar straight to
   <main id="main-content">. Off-canvas until it takes focus, then pinned top-left
   above the sticky topbar (z-index 50) and the sidebar. Gold fill with navy text is
   the primary-button pairing and clears AA contrast in both themes (neither token
   changes under [data-theme="light"]). Hub pages never load style.css, so this is
   the hub's own copy of that file's .skip-link. */
.skip-link {
    position: absolute;
    top: -100%;
    left: 0.5rem;
    z-index: 1000;
    padding: 0.5rem 0.75rem;
    background-color: var(--color-tuscan-yellow);
    color: var(--color-navy);
    font-weight: 700;
    font-size: 0.875rem;
    text-decoration: none;
    border-radius: 0 0 0.375rem 0.375rem;
    transition: top 0.15s ease;
}

.skip-link:focus {
    top: 0;
    color: var(--color-navy);
    outline: 2px solid var(--hub-blue);
    outline-offset: 2px;
}

/* The skip link's target. A landmark that just received focus does not need its
   own ring around the whole content column: the link that sent focus here showed one. */
.hub-content:focus {
    outline: none;
}

.hub-content {
    flex: 1;
    min-width: 0;
    padding: 2rem 2.5rem;
    /* Cap and center page content on wide monitors — without this every hub
       page hugs the left edge of a big browser window. */
    max-width: 1320px;
    margin-inline: auto;
    width: 100%;
    /* Systemic horizontal-overflow guard. A hidden-but-laid-out absolute child
       (e.g. a .pl-help__bubble tooltip anchored left:0 near the right edge, or a
       nowrap widget) still contributes to document scroll width, so the whole
       page scrolls sideways on a phone. html{overflow-x:hidden} does NOT contain
       it — the root's overflow propagates to the viewport (its own box computes
       to visible) and mobile Safari ignores it for panning anyway. `clip` here
       is the reliable stop: it trims horizontal overflow at the content column
       without creating a scroll container, keeps overflow-y visible so tooltips
       and menus still open downward, and never clips position:fixed modals
       (.hub-content isn't their containing block). */
    overflow-x: clip;
}

/* ========================================
   Messages
   ======================================== */
.hub-messages {
    list-style: none;
    margin-bottom: 1.5rem;
}

.hub-message {
    padding: 0.75rem 1rem;
    border-radius: 6px;
    font-size: 0.875rem;
    margin-bottom: 0.5rem;
    border-left: 3px solid;
}

.hub-message--success {
    color: var(--color-success);
    background-color: var(--color-success-bg);
    border-left-color: var(--color-success);
}

.hub-message--error {
    color: var(--color-error);
    background-color: var(--color-error-bg);
    border-left-color: var(--color-error);
}

.hub-message--info {
    color: var(--hub-text-muted);
    background-color: rgba(150, 172, 187, 0.1);
    border-left-color: var(--hub-text-muted);
}

/* ========================================
   Cards
   ======================================== */
.hub-card {
    background-color: var(--hub-card-bg);
    border: 1px solid var(--hub-card-border);
    border-radius: 10px;
    padding: 2rem;
}

/* Classes admin area (Overview sections + Settings hub cards): the dark theme's
   card border is transparent, so nested cards blend into the page. Give them a
   visible outline in dark mode; light keeps its existing card border. */
.cms-admin .hub-card {
    border-color: var(--hub-border);
}
[data-theme="light"] .cms-admin .hub-card {
    border-color: var(--hub-card-border);
}

.hub-page-title {
    font-size: 1.75rem;
    margin-bottom: 0.5rem;
}

.hub-text-muted {
    color: var(--hub-text-muted);
    font-size: 0.9375rem;
}

/* ========================================
   Vote List
   ======================================== */
.hub-vote-list {
    list-style: none;
    margin-top: 1rem;
}

.hub-vote-list li {
    padding: 0.5rem 0;
    font-size: 0.9375rem;
    border-bottom: 1px solid rgba(255,255,255,0.06);
}

[data-theme="light"] .hub-vote-list li {
    border-bottom-color: #e0ddd5;
}

.hub-vote-list li:last-child { border-bottom: none; }

.hub-success-icon {
    color: var(--color-success);
    margin-bottom: 1rem;
}

/* ========================================
   Forms
   ======================================== */
.hub-form-group {
    margin-bottom: 1.25rem;
}

.hub-form-group label {
    display: block;
    font-size: 0.8125rem;
    font-weight: 400;
    color: var(--hub-text-muted);
    margin-bottom: 0.375rem;
    letter-spacing: 0.02em;
}

.hub-form-group input[type="text"],
.hub-form-group input[type="search"],
.hub-form-group input[type="email"],
.hub-form-group input[type="tel"],
.hub-form-group input[type="number"],
.hub-form-group input[type="file"],
.hub-form-group input[type="url"],
.hub-form-group input[type="date"],
.hub-form-group select,
.hub-form-group textarea {
    width: 100%;
    padding: 0.625rem 0.875rem;
    font-family: var(--font-body);
    font-size: 0.9375rem;
    font-weight: 300;
    color: var(--hub-text);
    background-color: var(--hub-input-bg);
    border: 1px solid var(--hub-input-border);
    border-radius: 6px;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.hub-form-group textarea {
    resize: vertical;
    min-height: 120px;
}

.hub-form-group input:focus,
.hub-form-group select:focus,
.hub-form-group textarea:focus {
    outline: none;
    border-color: var(--color-tuscan-yellow);
    box-shadow: 0 0 0 3px rgba(238, 180, 75, 0.15);
}

.hub-form-group input:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* Native option popups don't inherit the select's colors (FRONTEND Rule 13). */
.hub-form-group select option {
    background: var(--hub-input-bg);
    color: var(--hub-text);
}

.hub-field-hint {
    display: block;
    font-size: 0.75rem;
    color: var(--hub-text-muted);
    margin-top: 0.25rem;
}

.hub-field-error {
    font-size: 0.8125rem;
    color: var(--color-error);
    margin-top: 0.25rem;
}

.hub-form-error {
    padding: 0.75rem 1rem;
    background-color: var(--color-error-bg);
    border-left: 3px solid var(--color-error);
    border-radius: 6px;
    color: var(--color-error);
    font-size: 0.875rem;
    margin-bottom: 1rem;
}

/* ========================================
   Fixed Feedback Button — bottom left
   ======================================== */
.pl-feedback-btn {
    position: fixed;
    bottom: 1.25rem;
    left: 1.25rem;
    z-index: 200;
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 1rem;
    font-family: var(--font-body);
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--hub-text-muted);
    background-color: var(--hub-card-bg);
    border: 1px solid var(--hub-input-border);
    border-radius: 8px;
    text-decoration: none;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
    transition: color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}

.pl-feedback-btn:hover {
    color: var(--color-tuscan-yellow);
    border-color: var(--color-tuscan-yellow);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}

.pl-feedback-btn svg {
    flex-shrink: 0;
    opacity: 0.7;
}

.pl-feedback-btn:hover svg {
    opacity: 1;
}

/* ========================================
   Buttons
   ======================================== */
.hub-btn {
    box-sizing: border-box;
    /* inline-block (not flex) so a button that contains a label plus an inline
       count/badge keeps the normal whitespace between them — flex would collapse
       the "All 185" space to "All185". Inline SVG icons self-center via their own
       vertical-align. */
    display: inline-block;
    padding: 0.625rem 1.5rem;
    font-family: var(--font-body);
    font-size: 0.9375rem;
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: 0.02em;
    /* The base paints itself as a ghost button. It used to set a transparent 1px border
       and no background at all, so a .hub-btn with no colour modifier fell through to the
       browser's own chrome: the document sets no color-scheme, so a bare <button> came
       back light-grey — louder than the green Approve beside it — and a bare <a> rendered
       as naked text. There are ~80 bare usages across templates/, so THIS EDIT HAS
       SITE-WIDE REACH: every one of them becomes a quiet outline button. Degrading to
       ghost rather than to a neutral fill is deliberate — --hub-elevated and --hub-card-bg
       are both #ffffff in Slate, so a filled base went white-on-white — and it adds no
       fourth button style to the design system: these are .hub-btn--ghost's own values.
       The border is still 1px, so bordered variants (success/danger/ghost) and borderless
       ones (primary) keep identical box math and render the exact same height;
       box-sizing: border-box keeps the border inside. The modifiers below win on source
       order. */
    background: transparent;
    color: var(--hub-text-muted);
    border: 1px solid var(--hub-border-strong);
    border-radius: 6px;
    text-decoration: none;
    cursor: pointer;
    transition: background-color 0.15s ease, transform 0.1s ease;
}

/* Neutral grey hover, so it reads the same over both themes' grounds. Each colour
   modifier re-declares its own :hover below and wins on source order. */
.hub-btn:hover {
    background: rgba(127, 127, 127, 0.1);
    color: var(--hub-text);
}

.hub-btn:active { transform: translateY(1px); }

.hub-btn:disabled,
.hub-btn[disabled] {
    opacity: 0.4;
    cursor: not-allowed;
}
.hub-btn:disabled:active { transform: none; }

.hub-btn--primary {
    background-color: var(--color-tuscan-yellow);
    color: var(--color-navy);
    /* The only modifier that paints no border of its own: it relied on inheriting the
       base's transparent border colour, which the ghost degrade above took away. */
    border-color: transparent;
}

.hub-btn--primary:hover {
    background-color: var(--color-yellow-hover);
    color: var(--color-navy);
}

.hub-btn--danger {
    background: #c0392b;
    color: #fff;
    border: 1px solid #c0392b;
}
.hub-btn--danger:hover {
    background: #d94a3d;
    border-color: #d94a3d;
    color: #fff;
}

/* Positive/confirming action (e.g. "Approve"). Always green. */
.hub-btn--success {
    background: #2f8f4e;
    color: #fff;
    border: 1px solid #2f8f4e;
}
.hub-btn--success:hover {
    background: #37a259;
    border-color: #37a259;
    color: #fff;
}

/* Small size modifier for table-row / inline actions. */
.hub-btn--sm {
    padding: 0.3rem 0.7rem;
    font-size: 0.8125rem;
    border-radius: 4px;
}

/* Low-emphasis inline action (e.g. "Edit" in a table row). */
.hub-btn--ghost {
    background: transparent;
    color: var(--hub-text-muted);
    border: 1px solid var(--hub-border-strong);
}
.hub-btn--ghost:hover {
    background: rgba(255, 255, 255, 0.06);
    color: var(--hub-text);
    border-color: var(--hub-text-muted);
}

/* ========================================
   Guild Detail
   ======================================== */
.hub-detail-section {
    margin-top: 1.5rem;
}

.hub-detail-label {
    font-family: var(--font-body);
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--hub-text-muted);
    margin-bottom: 0.75rem;
}

.hub-member-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.625rem 0;
}

.hub-member-avatar {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background-color: rgba(238, 180, 75, 0.15);
    color: var(--color-tuscan-yellow);
    font-size: 0.8125rem;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
}

.hub-member-info {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.hub-member-name {
    font-size: 0.9375rem;
    font-weight: 400;
}

.hub-badge {
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    padding: 0.125rem 0.5rem;
    border-radius: 10px;
    background-color: rgba(238, 180, 75, 0.15);
    color: var(--color-tuscan-yellow);
}

/* Alpine x-show reveal (e.g. the "schedule for later" datetime picker). A plain
   display:block class — never an inline style="display:…", which x-show strips on
   first reveal (FRONTEND.md rule 12). */
.pl-reveal {
    display: block;
    margin-top: 1rem;
}

/* A staff member's titles shown together as badges — wraps on narrow screens. */
.pl-badge-group {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.375rem;
}

/* One title badge plus its per-title Remove control on the Staff tab. */
.pl-staff-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
}

.hub-note {
    font-size: 0.8125rem;
    font-style: italic;
}


/* ========================================
   Members Table (Manage Members)
   Token-driven; stacks into labelled cards on phones (no horizontal scroll).
   ======================================== */
.pl-members-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9375rem;
    overflow-x: hidden;
}
.pl-members-table th,
.pl-members-table td {
    padding: 0.55rem 0.75rem;
}
.pl-members-table th {
    text-align: left;
    color: var(--hub-text-muted);
    font-weight: 500;
    font-size: 0.875rem;
}
.pl-members-table td {
    color: var(--hub-text-muted);
}
.pl-members-table td:first-child {
    color: var(--hub-text); /* Name column reads as primary text (two-tone rows) */
}
.pl-members-table tr {
    border-bottom: 1px solid var(--hub-border);
}

@media (max-width: 768px) {
    .pl-members-table thead {
        display: none;
    }
    .pl-members-table tr {
        display: block;
        border: 1px solid var(--hub-border);
        border-radius: 8px;
        margin-bottom: 0.75rem;
        padding: 0.25rem 0.75rem;
    }
    .pl-members-table td[data-label] {
        display: block;
        padding: 0.4rem 0;
        overflow-wrap: anywhere;
    }
    .pl-members-table td[data-label]::before {
        content: attr(data-label);
        display: block;
        color: var(--hub-text-muted);
        font-weight: 500;
        font-size: 0.75rem;
        text-transform: uppercase;
        letter-spacing: 0.04em;
        margin-bottom: 0.15rem;
    }
}


/* ========================================
   Mobile Sidebar Backdrop
   ======================================== */
.hub-sidebar-backdrop {
    display: none;
}

/* ========================================
   Responsive
   ======================================== */
@media (max-width: 768px) {
    .hub-sidebar {
        transform: translateX(-100%);
        box-shadow: none;
        transition: transform 0.25s ease, box-shadow 0.25s ease;
    }

    /* On mobile, sidebar is visible when NOT closed */
    .hub-sidebar:not(.hub-sidebar--closed) {
        transform: translateX(0);
        box-shadow: 4px 0 24px rgba(0, 0, 0, 0.4);
    }

    .hub-sidebar-backdrop {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 99;
        background-color: rgba(0, 0, 0, 0.5);
        opacity: 0;
        pointer-events: none;
        transition: opacity 0.25s ease;
    }

    .hub-sidebar-backdrop--visible {
        opacity: 1;
        pointer-events: auto;
    }

    .hub-main-wrapper { margin-left: 0; }

    .hub-content {
        padding: 1.5rem 1rem;
    }

    .hub-card {
        padding: 1.25rem;
    }
}

/* ========================================
   Member Directory
   ======================================== */
.directory-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: 1rem;
}

.directory-card {
    background-color: var(--hub-card-bg);
    border: 1px solid var(--hub-input-border);
    border-radius: 10px;
    padding: 1.25rem;
}

.directory-card__header {
    display: flex;
    gap: 0.75rem;
    align-items: flex-start;
}

.directory-card__avatar {
    flex-shrink: 0;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background-color: rgba(238, 180, 75, 0.15);
    color: var(--color-tuscan-yellow);
    font-size: 0.75rem;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    letter-spacing: 0.03em;
}

.directory-card__identity {
    min-width: 0;
}

.directory-card__name {
    font-weight: 600;
    font-size: 1rem;
    color: var(--hub-text);
    line-height: 1.3;
}

.directory-card__preferred {
    font-size: 0.85rem;
    color: var(--hub-text-muted);
    font-style: italic;
}

.directory-card__meta {
    display: flex;
    gap: 0.75rem;
    margin-top: 0.25rem;
    font-size: 0.8rem;
    color: var(--hub-text-muted);
}

.directory-card__role {
    font-weight: 500;
}

.directory-card__about {
    margin: 0.75rem 0 0;
    font-size: 0.9rem;
    color: var(--hub-text-muted);
    line-height: 1.5;
}

.directory-card__contact {
    margin-top: 0.75rem;
    padding-top: 0.75rem;
    border-top: 1px solid var(--hub-input-border);
}

.directory-card__contact-row {
    display: flex;
    gap: 0.5rem;
    font-size: 0.85rem;
    padding: 0.2rem 0;
    color: var(--hub-text-muted);
}

.directory-card__contact-row a {
    color: var(--color-tuscan-yellow);
    text-decoration: none;
}

.directory-card__contact-row a:hover {
    text-decoration: underline;
}

.directory-card__contact-label {
    font-weight: 500;
    color: var(--hub-text);
    min-width: 4rem;
    flex-shrink: 0;
}

.directory-card__role-mgmt {
    margin-top: 0.75rem;
    padding-top: 0.75rem;
    border-top: 1px solid var(--hub-input-border);
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.directory-card__role-form {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex: 1;
}

.directory-card__role-select {
    flex: 1;
    padding: 0.375rem 0.5rem;
    font-size: 0.8rem;
    font-family: var(--font-body);
    color: var(--hub-text);
    background-color: var(--hub-input-bg);
    border: 1px solid var(--hub-input-border);
    border-radius: 6px;
    cursor: pointer;
}

.directory-card__role-select:focus {
    outline: none;
    border-color: var(--color-tuscan-yellow);
}

.directory-card__role-btn {
    padding: 0.375rem 0.75rem;
    font-size: 0.8rem;
    font-weight: 600;
    font-family: var(--font-body);
    color: var(--color-navy);
    background-color: var(--color-tuscan-yellow);
    border: none;
    border-radius: 6px;
    cursor: pointer;
    transition: background-color 0.15s ease;
    white-space: nowrap;
}

.directory-card__role-btn:hover {
    background-color: var(--color-yellow-hover);
}

/* ========================================
   Changelog Modal
   ======================================== */
.changelog-overlay {
    position: fixed;
    inset: 0;
    z-index: 9999;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: rgba(0, 0, 0, 0.6);
    padding: 1rem;
}

.changelog-modal {
    background-color: var(--hub-card-bg);
    border-radius: 12px;
    border: 1px solid var(--hub-input-border);
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
    max-width: 520px;
    width: 100%;
    max-height: 80vh;
    display: flex;
    flex-direction: column;
}

.changelog-modal__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 1rem 1.5rem;
    border-bottom: 1px solid var(--hub-input-border);
}

.changelog-modal__title {
    font-family: var(--font-heading);
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--hub-text);
    margin: 0;
}

.changelog-modal__close {
    background: none;
    border: none;
    font-size: 1.5rem;
    cursor: pointer;
    color: var(--hub-text-muted);
    padding: 0;
    line-height: 1;
}

.changelog-modal__close:hover {
    color: var(--hub-text);
}

.changelog-modal__body {
    padding: 1.5rem;
    overflow-y: auto;
}

.changelog-entry + .changelog-entry {
    margin-top: 1.5rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--hub-input-border);
}

.changelog-entry__header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.25rem;
}

.changelog-entry__version {
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    padding: 0.125rem 0.5rem;
    border-radius: 10px;
    background-color: rgba(238, 180, 75, 0.15);
    color: var(--color-tuscan-yellow);
}

.changelog-entry__date {
    font-size: 0.8rem;
    color: var(--hub-text-muted);
}

.changelog-entry__title {
    font-family: var(--font-heading);
    font-size: 1rem;
    font-weight: 600;
    color: var(--hub-text);
    margin: 0 0 0.5rem 0;
}

.changelog-entry__list {
    list-style: none;
    padding: 0;
    margin: 0;
}

.changelog-entry__list li {
    font-size: 0.9rem;
    color: var(--hub-text-muted);
    padding: 0.3rem 0;
    padding-left: 1rem;
    position: relative;
}

.changelog-entry__list li::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0.7rem;
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background-color: var(--color-tuscan-yellow);
}

/* ========================================
   Tab Balance Pill (topbar)
   ======================================== */
.pl-topbar__tab-pill {
    display: inline-flex;
    align-items: center;
    padding: 0.25rem 0.6rem;
    font-size: 0.75rem;
    font-weight: 600;
    font-family: var(--font-body);
    color: var(--hub-text);
    background: rgba(255,255,255,0.08);
    border: 1px solid rgba(255,255,255,0.12);
    border-radius: 12px;
    text-decoration: none;
    margin-right: 0.5rem;
    transition: background 150ms ease;
}
.pl-topbar__tab-pill:hover {
    background: rgba(255,255,255,0.14);
    color: var(--hub-text);
}
.pl-topbar__tab-pill--locked {
    background: rgba(240, 100, 100, 0.2);
    border-color: rgba(240, 100, 100, 0.4);
    color: var(--color-error);
}
[data-theme="light"] .pl-topbar__tab-pill {
    background: rgba(0,0,0,0.06);
    border-color: rgba(0,0,0,0.12);
    color: #333;
}
[data-theme="light"] .pl-topbar__tab-pill:hover {
    background: rgba(0,0,0,0.1);
    color: #333;
}

/* ========================================
   Tab Pages
   ======================================== */
.tab-page-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.5rem;
}
.tab-page-header .hub-page-title { margin-bottom: 0; }
.tab-page-header__title {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}
.tab-page-header__title-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}
.tab-page-header__subtext {
    margin: 0;
    font-size: 0.8125rem;
    color: var(--hub-text-muted, #96ACBB);
}

/* Hoverable help bubble — used next to section titles */
.pl-help {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: help;
}
.pl-help__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.125rem;
    height: 1.125rem;
    border-radius: 50%;
    background: var(--hub-input-border, #334155);
    color: var(--hub-text, #F4EFDD);
    font-size: 0.75rem;
    font-weight: 700;
    line-height: 1;
    user-select: none;
}
.pl-help__bubble {
    position: absolute;
    top: calc(100% + 0.5rem);
    left: 0;
    z-index: 50;
    width: max-content;
    max-width: 320px;
    padding: 0.75rem 0.875rem;
    background: var(--hub-card-bg, #0b1f33);
    color: var(--hub-text, #F4EFDD);
    border: 1px solid var(--hub-input-border, #334155);
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
    font-size: 0.8125rem;
    line-height: 1.45;
    white-space: normal;
    /* Own the bubble's typography — it must read as plain prose even when placed
       inside an uppercased/letter-spaced/bold context (e.g. the notifications
       matrix column header), not inherit those. */
    text-transform: none;
    letter-spacing: normal;
    font-weight: 400;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-4px);
    transition: opacity 0.15s ease, transform 0.15s ease, visibility 0.15s;
    pointer-events: none;
}
.pl-help:hover .pl-help__bubble,
.pl-help:focus-within .pl-help__bubble {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}
/* Right-anchored variant for bubbles in the narrow right-hand aside — a
   left-anchored 320px bubble would overflow the viewport there. */
.pl-help--right .pl-help__bubble {
    left: auto;
    right: 0;
}
/* Lifted by static/js/pl_help.js on desktop: the bubble is re-anchored to the viewport
   (inline position: fixed, top, left) so an overflow: hidden or overflow: auto ancestor
   (.admin-table-wrap, every scrolling table) cannot clip it. Only the stacking order
   lives here; the hover and focus reveal above is untouched. */
.pl-help[data-help-lifted] .pl-help__bubble {
    z-index: 1000;
}

/* Phone: the bubble is up to 320px and anchored to a tiny icon that can sit
   anywhere in a narrow column, so left/right:0 always pokes one edge off-screen
   (the page-scroll bug this component drove). Neither anchor fits a 320px bubble
   on a 393px screen. Pin it to the viewport gutters instead so it is always fully
   readable, regardless of where the icon sits. Fixed (not absolute) so it escapes
   the .hub-content clip and is measured against the viewport; it stays hidden until
   hover/focus, so it never contributes to page width. Anchored just under the
   sticky topbar (not the bottom, which the floating chat button owns). */
@media (max-width: 768px) {
    .pl-help__bubble,
    .pl-help--right .pl-help__bubble {
        position: fixed;
        left: 1rem;
        right: 1rem;
        top: calc(var(--topbar-height) + env(safe-area-inset-top, 0px) + 0.5rem);
        bottom: auto;
        width: auto;
        max-width: none;
        transform: translateY(-6px);
    }
    .pl-help:hover .pl-help__bubble,
    .pl-help:focus-within .pl-help__bubble {
        transform: translateY(0);
    }
}

.tab-history-link {
    font-size: 0.85rem;
    color: var(--color-tuscan-yellow);
    text-decoration: none;
}
.tab-history-link:hover { text-decoration: underline; }

/* Banners */
.tab-banner {
    padding: 0.75rem 1rem;
    border-radius: 8px;
    margin-bottom: 1rem;
    font-size: 0.9rem;
}
.tab-banner--error {
    background: var(--color-error-bg);
    color: var(--color-error);
    border: 1px solid rgba(240, 160, 160, 0.25);
}
.tab-banner--warning {
    background: rgba(238, 180, 75, 0.12);
    color: var(--color-tuscan-yellow);
    border: 1px solid rgba(238, 180, 75, 0.25);
}

/* Summary card */
.tab-summary { margin-bottom: 1rem; }
.tab-summary__row {
    display: flex;
    justify-content: space-between;
    padding: 0.5rem 0;
}
.tab-summary__row + .tab-summary__row {
    border-top: 1px solid var(--hub-topbar-border);
}
.tab-summary__label {
    font-size: 0.9rem;
    color: var(--hub-text-muted);
}
.tab-summary__value {
    font-size: 0.9rem;
    font-weight: 600;
}
.tab-summary__value--balance {
    font-size: 1.1rem;
    color: var(--color-tuscan-yellow);
}

/* Pending checkout — direct-keys "Pay Now" list */
.tab-checkout-list {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}
.tab-checkout-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.875rem 1rem;
    background: rgba(238, 180, 75, 0.08);
    border: 1px solid rgba(238, 180, 75, 0.3);
    border-radius: 8px;
    gap: 1rem;
}
.tab-checkout-item__title {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--hub-text);
}
.tab-checkout-item__meta {
    font-size: 0.8rem;
    color: var(--hub-text-muted);
    margin-top: 0.125rem;
}
.tab-checkout-item__btn {
    flex-shrink: 0;
    padding: 0.5rem 1rem;
    background: var(--color-tuscan-yellow);
    color: #1a1a1a;
    border-radius: 6px;
    font-size: 0.875rem;
    font-weight: 600;
    text-decoration: none;
    transition: filter 0.15s ease;
}
.tab-checkout-item__btn:hover {
    filter: brightness(1.1);
}

/* Guild detail — product card grid */
.guild-product-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 0.875rem;
}
.guild-product-card {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 1rem;
    background: rgba(255, 255, 255, 0.03);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 10px;
    transition: border-color 0.15s ease, background 0.15s ease;
    min-height: 90px;
}
.guild-product-card:hover {
    border-color: rgba(238, 180, 75, 0.4);
    background: rgba(238, 180, 75, 0.05);
}
.guild-product-card__name {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--hub-text);
    line-height: 1.3;
}
.guild-product-card__price {
    font-size: 1.25rem;
    font-weight: 700;
    color: var(--hub-link);
}
.guild-product-card__splits {
    font-size: 0.75rem;
    color: var(--hub-text-muted);
    line-height: 1.3;
    margin-top: -0.1rem;
}
.guild-product-card__add-form {
    margin-top: 0.5rem;
}
.guild-product-card__add-btn {
    width: 100%;
    padding: 0.4rem 0.6rem;
    background: var(--color-tuscan-yellow);
    color: #1a1a2e;
    border: none;
    border-radius: 6px;
    font-weight: 600;
    font-size: 0.8rem;
    cursor: pointer;
    transition: background 0.15s ease;
}
.guild-product-card__add-btn:hover {
    background: var(--color-yellow-hover);
}

/* Enter-Your-Own-Price card — first card in the product grid */
.guild-product-card--eyop {
    align-items: center;
    text-align: center;
    border-style: dashed;
    border-color: rgba(238, 180, 75, 0.4);
}
.guild-product-card--eyop:hover {
    border-color: rgba(238, 180, 75, 0.8);
    background: rgba(238, 180, 75, 0.08);
}
.guild-product-card__subtext {
    font-size: 0.8125rem;
    color: var(--hub-text-muted);
    margin-top: -0.25rem;
}
.guild-product-card__eyop-plus {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 48px;
    height: 48px;
    margin: 0.25rem auto 0.25rem;
    background: var(--color-tuscan-yellow);
    border: none;
    border-radius: 50%;
    color: #1a1a2e;
    cursor: pointer;
    transition: background 0.15s ease, transform 0.15s ease;
}
.guild-product-card__eyop-plus:hover {
    background: var(--color-yellow-hover);
    transform: scale(1.05);
}

/* Trash-can remove button on the My Tab table */
.tab-table__remove {
    background: transparent;
    border: none;
    padding: 0;
    cursor: pointer;
    line-height: 1;
    color: #dc2626;
    transition: color 0.15s ease, transform 0.15s ease;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.tab-table__remove svg {
    stroke: #dc2626;
}
.tab-table__remove:hover {
    color: #ef4444;
    transform: scale(1.15);
}
.tab-table__remove:hover svg {
    stroke: #ef4444;
}

/* Shared table */
.tab-section-title {
    font-size: 1rem;
    font-weight: 600;
    margin-bottom: 0.75rem;
}
.tab-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.85rem;
}
.tab-table th {
    text-align: left;
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--hub-topbar-border);
    font-weight: 500;
    color: var(--hub-text-muted);
}
.tab-table td {
    padding: 0.5rem 0.75rem;
}
.tab-table th.tab-table__right,
.tab-table td.tab-table__right { text-align: right; }
.tab-table__date {
    font-size: 0.8rem;
    color: var(--hub-text-muted);
}

/* Add to Tab form */
.tab-add-form__fields {
    display: flex;
    gap: 0.75rem;
    align-items: flex-end;
    flex-wrap: wrap;
}
.tab-add-form__field {
    flex: 1;
    min-width: 150px;
}
.tab-add-form__field--amount {
    flex: 0 0 120px;
    min-width: 100px;
}
.tab-add-form__field label {
    display: block;
    font-size: 0.8rem;
    color: var(--hub-text-muted);
    margin-bottom: 0.25rem;
}
.tab-add-form__field input {
    width: 100%;
    padding: 0.5rem 0.6rem;
    background: var(--hub-input-bg);
    border: 1px solid var(--hub-input-border);
    border-radius: 6px;
    color: var(--hub-text);
    font-size: 0.85rem;
}
.tab-add-form__btn {
    padding: 0.5rem 1rem;
    background: var(--color-tuscan-yellow);
    color: #1a1a2e;
    border: none;
    border-radius: 6px;
    font-weight: 600;
    font-size: 0.85rem;
    cursor: pointer;
    white-space: nowrap;
}
.tab-add-form__btn:hover {
    background: var(--color-yellow-hover);
}
.tab-form-error {
    display: block;
    font-size: 0.75rem;
    color: var(--color-error);
    margin-top: 0.25rem;
}

/* Tab History — charge cards */
.tab-charge {
    border-bottom: 1px solid var(--hub-topbar-border);
}
.tab-charge:last-child { border-bottom: none; }
.tab-charge__header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0.75rem 0;
}
.tab-charge__info {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
}
.tab-charge__date {
    font-size: 0.9rem;
    font-weight: 500;
}
.tab-charge__status {
    font-size: 0.75rem;
    padding: 0.15rem 0.5rem;
    border-radius: 10px;
    font-weight: 600;
}
.tab-charge__status--succeeded {
    background: var(--color-success-bg);
    color: var(--color-success);
}
.tab-charge__status--failed {
    background: var(--color-error-bg);
    color: var(--color-error);
}
.tab-charge__status--processing {
    background: rgba(238, 180, 75, 0.12);
    color: var(--color-tuscan-yellow);
}
.tab-charge__count {
    font-size: 0.8rem;
    color: var(--hub-text-muted);
}
.tab-charge__amount {
    font-weight: 600;
    font-size: 0.95rem;
}
.tab-charge__details {
    padding: 0 0 0.75rem;
}
.tab-charge__receipt-link {
    display: inline-block;
    margin-top: 0.5rem;
    font-size: 0.8rem;
    color: var(--color-tuscan-yellow);
    text-decoration: none;
}
.tab-charge__receipt-link:hover { text-decoration: underline; }
.tab-entry-guild {
    font-size: 0.75rem;
    color: var(--hub-text-muted);
    opacity: 0.8;
}
.tab-charge__destination {
    font-size: 0.8rem;
    color: var(--hub-text-muted);
}

/* ========================================
   Guild page — Edit / Add Product modals
   ======================================== */

/* Header row — title + action buttons on the guild detail page. */
.pl-guild-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1rem;
}
.pl-guild-header .hub-page-title {
    margin: 0;
}
.pl-guild-header__actions {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
}

/* Edit Guild + Add Product form shells used inside the modal. */
.pl-guild-edit-form,
.pl-product-form form {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}
.pl-guild-edit-form__actions,
.pl-product-form__actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.75rem;
    margin-top: 0.5rem;
}

/* Inputs inside these modal forms. Mirrors the .pl-form-group styling from
   components.css but scoped so we can use standalone <input>/<textarea>
   without the wrapper class. */
.pl-guild-edit-form input[type="text"],
.pl-guild-edit-form textarea,
.pl-product-form input[type="text"],
.pl-product-form input[type="number"],
.pl-product-form select {
    background: var(--hub-input-bg, rgba(255, 255, 255, 0.06));
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 6px;
    color: var(--hub-text, #F4EFDD);
    padding: 0.5rem 0.75rem;
    font-size: 0.875rem;
    width: 100%;
    box-sizing: border-box;
    transition: border-color 0.15s ease;
}
.pl-guild-edit-form input[type="text"]:focus,
.pl-guild-edit-form textarea:focus,
.pl-product-form input[type="text"]:focus,
.pl-product-form input[type="number"]:focus,
.pl-product-form select:focus {
    border-color: var(--color-tuscan-yellow, #EEB44B);
    outline: none;
    box-shadow: 0 0 0 3px rgba(238, 180, 75, 0.15);
}

/* Two-column row for Name + Price. */
.pl-product-form__row {
    display: flex;
    gap: 1rem;
    flex-wrap: wrap;
}
.pl-product-form__row .pl-form-group {
    flex: 1 1 180px;
    min-width: 0;
}

/* Revenue-splits fieldset inside the Add Product modal. */
.pl-product-form__splits {
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.02);
    padding: 1rem 1.25rem 1.25rem;
    margin: 0;
}
.pl-product-form__splits > legend {
    padding: 0 0.5rem;
    font-size: 0.75rem;
    font-weight: 700;
    color: var(--hub-text-muted, #96ACBB);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.pl-splits {
    width: 100%;
    border-collapse: collapse;
    margin: 0.25rem 0 0.75rem;
}
.pl-splits thead th {
    text-align: left;
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--hub-text-muted, #96ACBB);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    padding: 0.25rem 0.5rem;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}
.pl-splits tbody td {
    padding: 0.375rem 0.5rem;
    vertical-align: middle;
    color: var(--hub-text, #F4EFDD);
    font-size: 0.875rem;
}
.pl-splits__percent {
    white-space: nowrap;
    width: 30%;
}
.pl-splits__percent input[type="number"] {
    display: inline-block;
    width: 6rem !important;
    margin-right: 0.35rem;
}
.pl-splits__actions {
    text-align: right;
    width: auto;
}
.pl-splits__remove {
    background: rgba(224, 85, 85, 0.1);
    color: #e05555;
    border: none;
    border-radius: 4px;
    width: 1.75rem;
    height: 1.75rem;
    font-size: 1.1rem;
    line-height: 1;
    cursor: pointer;
    transition: background 0.15s ease;
}
.pl-splits__remove:hover {
    background: rgba(224, 85, 85, 0.25);
}
.pl-splits__add {
    margin-top: 0.25rem;
}
.pl-splits__preview {
    margin: 0.5rem 0 0.25rem;
    font-size: 0.8125rem;
    font-style: italic;
    color: var(--hub-text-muted, #96ACBB);
}
.pl-splits__total {
    margin: 0.75rem 0 0;
    font-size: 0.9375rem;
    font-weight: 700;
}
.pl-splits__total--ok {
    color: #7bc88f;
}
.pl-splits__total--bad {
    color: #f0a0a0;
}

/* Small delete button on each existing product card. */
.guild-product-card {
    position: relative;
}
.guild-product-card__delete-btn {
    position: absolute;
    top: 0.35rem;
    right: 0.35rem;
    background: rgba(224, 85, 85, 0.15);
    color: #e05555;
    border: none;
    border-radius: 4px;
    width: 1.5rem;
    height: 1.5rem;
    font-size: 1rem;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    cursor: pointer;
    transition: background 0.15s ease;
    padding: 0;
}
.guild-product-card__delete-btn:hover {
    background: rgba(224, 85, 85, 0.3);
}
.guild-product-card__edit-btn {
    position: absolute;
    top: 0.35rem;
    right: 2rem;
    background: rgba(238, 180, 75, 0.15);
    color: var(--color-tuscan-yellow, #eeb44b);
    border: none;
    border-radius: 4px;
    width: 1.5rem;
    height: 1.5rem;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    cursor: pointer;
    transition: background 0.15s ease;
}
.guild-product-card__edit-btn:hover {
    background: rgba(238, 180, 75, 0.3);
}

/* Viewing-as popover */
.pl-view-as-popover {
    position: relative;
}

.pl-view-as-popover__menu {
    position: absolute;
    top: calc(100% + 6px);
    /* The trigger sits on the left side of the topbar — grow rightward.
       (right: 0 pushed the menu off the left screen edge.) */
    left: 0;
    min-width: 200px;
    background: var(--hub-dropdown-bg);
    border: 1px solid var(--hub-dropdown-border);
    border-radius: 8px;
    padding: 8px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.35);
    z-index: 50;
}

@media (max-width: 768px) {
    /* The trigger sits near the left edge of the topbar, so an absolute
       right-0 menu extends off-screen left on phones. Pin to the viewport
       just below the topbar instead. */
    .pl-view-as-popover__menu {
        position: fixed;
        top: calc(var(--topbar-height) + env(safe-area-inset-top, 0px) + 6px);
        left: 8px;
        right: 8px;
        min-width: 0;
        /* 5rem bottom clearance keeps the feedback FAB (fixed, z-95, outside
           the topbar stacking context) from covering the last duty toggle. */
        max-height: calc(100dvh - var(--topbar-height) - env(safe-area-inset-top, 0px) - 5rem);
        overflow-y: auto;
    }
}

.pl-view-as-popover__header {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    opacity: 0.6;
    padding: 4px 8px 8px;
}

.pl-view-as-popover__row {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 7px 10px;
    border: none;
    background: none;
    color: inherit;
    text-align: left;
    border-radius: 6px;
    cursor: pointer;
    font-size: 14px;
    font-family: inherit;
}

.pl-view-as-popover__row:hover {
    background: rgba(255, 255, 255, 0.05);
}

.pl-view-as-popover__row--selected {
    background: rgba(255, 255, 255, 0.04);
    font-weight: 600;
}

.pl-view-as-popover__check {
    opacity: 0.7;
    font-size: 12px;
}

.pl-view-as-popover__hint {
    font-size: 11px;
    opacity: 0.55;
    padding: 8px;
    border-top: 1px solid var(--hub-dropdown-border);
    margin-top: 4px;
}

.pl-view-as-popover__duties {
    /* Wide enough that the longest duty name plus its "?" bubble stays on one line. */
    min-width: 284px;
    margin-top: 4px;
    border-top: 1px solid var(--hub-dropdown-border);
}

/* Doubled-up class so this beats components.css's own .pl-toggle-row padding — that
   sheet loads after this one, and its 1rem rows made the popover tall enough to run
   off the bottom of a short laptop screen. */
.pl-view-as-popover__duty.pl-toggle-row {
    padding: 6px 8px;
    gap: 12px;
    border-bottom: none;
}

.pl-view-as-popover__duty .pl-toggle-label {
    font-size: 13px;
    font-weight: 400;
}

/* The "?" help bubble trails the duty name in normal text flow (not a flex item), so on a
   two-line name it sits right after the last word instead of floating beside the block. */
.pl-view-as-popover__duty .pl-help {
    margin-left: 5px;
    vertical-align: -0.15em;
}

/* Scaled to the popover's 13px rows — the page-level 1.125rem icon dwarfs them. */
.pl-view-as-popover__duty .pl-help__icon {
    width: 0.9375rem;
    height: 0.9375rem;
    font-size: 0.625rem;
}

.pl-view-as-popover__duties .pl-view-as-popover__hint {
    border-top: 1px solid var(--hub-dropdown-border);
}

.hub-sidebar__icons {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 1rem;
    padding: 0.5rem 0.75rem 0.625rem;
}

.hub-sidebar__icon-link {
    display: inline-flex;
    align-items: center;
    color: rgba(244, 239, 221, 0.4);
    text-decoration: none;
    transition: color 0.15s ease;
    line-height: 0;
}

.hub-sidebar__icon-link:hover {
    color: var(--color-tuscan-yellow);
}

/* "Get the app" badges under the icon row (#467, templates/includes/app_store_badges.html; the
   component itself is in components.css). Stacked, not inline: two badges at Apple's 40px floor
   are wider than the 220px sidebar. */
.pl-app-badges--tray {
    align-items: center;
    padding: 0 0.75rem 0.5rem;
}

.pl-app-badges--tray .pl-app-badges__links {
    flex-direction: column;
    gap: 0.375rem;
}

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ========================================
   Public Top Bar (anonymous visitors)
   Used on Classes & Workshops, register, etc. when no user is logged in.
   ======================================== */
.pl-public-topbar {
    position: sticky;
    top: 0;
    z-index: 50;
    /* Grow by the status-bar/notch inset, exactly as .pl-topbar does — the app
       webview is edge-to-edge (viewport-fit=cover), so the bar keeps its brand
       and nav below the system UI.
       Two different mechanisms carry that inset, and which one a declaration
       needs depends on whether its value contains var():
       - No var() (the `padding` below): an engine that cannot parse env()
         throws out the WHOLE declaration at parse time, so writing the plain
         line FIRST and the env() line immediately after is a real fallback
         pair. Do not collapse it into the env() line on its own.
       - Contains var() (`height`): a declaration holding var() is stored as an
         unvalidated token stream and only checked after substitution, so it
         WINS the cascade on that engine and then computes to `auto` — a bar
         collapsed to content height, not a fallback. The pair trick does
         nothing there, so the height inset lives in the @supports block just
         below this rule, which such an engine skips whole. */
    height: var(--topbar-height);
    background-color: rgba(6, 31, 51, 0.85);
    backdrop-filter: blur(18px);
    -webkit-backdrop-filter: blur(18px);
    border-bottom: 1px solid rgba(238, 180, 75, 0.18);
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 1.5rem;
    padding: env(safe-area-inset-top, 0px) 1.5rem 0;
    gap: 1rem;
    /* A flex item floors at min-content unless told otherwise, so without this
       nothing inside the bar can ever shrink and the row overflows its own
       header. The same declaration repeats on the brand and the label. */
    min-width: 0;
}
/* The height half of the inset. @supports is parse-tested, so an engine that
   cannot parse env() never enters this block and keeps the plain height above;
   one that can gets the taller bar. Keep this after the base rule and ahead of
   the breakpoints — neither @media block declares height, so nothing later
   re-declares it at equal specificity. */
@supports (height: env(safe-area-inset-top)) {
    .pl-public-topbar {
        height: calc(var(--topbar-height) + env(safe-area-inset-top, 0px));
    }
}
.pl-public-topbar__brand {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    color: var(--color-cream, #f4efdd);
    font-family: 'Playfair Display', Georgia, serif;
    font-weight: 800;
    font-size: 16px;
    text-decoration: none;
    min-width: 0;
}
.pl-public-topbar__brand:hover { text-decoration: none; opacity: 0.9; }
/* The logo is the one thing that never gives way — a shrunk 22px mark reads as
   a rendering fault, not as a responsive layout. */
.pl-public-topbar__brand img { flex: 0 0 auto; }
/* The truncation guard lives on the label, never on __brand: __brand is
   inline-flex, where text-overflow is a no-op and the text hard-clips
   mid-glyph instead of ellipsising. min-width: 0 repeats down the whole chain
   (bar → brand → label) because each flex item's default min-width: auto
   defeats the one above it. */
.pl-public-topbar__label {
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}
/* __name and __wordmark split the brand text into two halves so the 480px block
   below can drop " Member Portal" and keep the short name. They carry no
   declarations here on purpose: __label's white-space: nowrap inherits down to
   both, so repeating it would be inert. The spans exist as markup hooks, and
   __wordmark's only rule is the display: none in the 480px block. */
.pl-public-topbar__nav {
    display: inline-flex;
    align-items: center;
    gap: 14px;
    /* The nav holds its laid-out size; the brand is what shrinks. Narrowing is
       done by the breakpoints below dropping items, not by squashing them. */
    flex: 0 0 auto;
}
.pl-public-topbar__link {
    color: var(--color-steel, #96acbb);
    font-size: 13px;
    font-weight: 600;
    text-decoration: none;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.pl-public-topbar__link:hover { color: var(--color-tuscan-yellow, #EEB44B); text-decoration: none; }
.pl-public-topbar__signup {
    background: var(--color-tuscan-yellow, #EEB44B);
    color: #061f33;
    padding: 8px 18px;
    border-radius: 4px;
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    text-decoration: none;
}
.pl-public-topbar__signup:hover { background: #f5ca6e; text-decoration: none; }
.pl-public-topbar__login {
    color: var(--color-tuscan-yellow, #EEB44B);
    padding: 8px 14px;
    border-radius: 4px;
    border: 1px solid rgba(238, 180, 75, 0.45);
    background: rgba(238, 180, 75, 0.06);
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    text-decoration: none;
}
.pl-public-topbar__login:hover {
    background: rgba(238, 180, 75, 0.18);
    text-decoration: none;
}
.pl-public-topbar__exit-preview {
    background: rgba(238, 180, 75, 0.12);
    color: var(--color-tuscan-yellow, #EEB44B);
    border: 1px solid rgba(238, 180, 75, 0.4);
    padding: 7px 14px;
    border-radius: 4px;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    text-decoration: none;
    white-space: nowrap;
}
.pl-public-topbar__exit-preview:hover {
    background: rgba(238, 180, 75, 0.22);
    text-decoration: none;
}

.pl-public-topbar__ext {
    color: var(--color-tuscan-yellow, #EEB44B);
    font-size: 13px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 8px 12px;
    border-radius: 4px;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.pl-public-topbar__ext:hover { background: rgba(238, 180, 75, 0.08); text-decoration: none; }

.pl-public-topbar__pill {
    display: inline-block;
    font-size: 9px;
    font-weight: 800;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    padding: 3px 8px;
    border-radius: 999px;
    background: rgba(238, 180, 75, 0.12);
    border: 1px solid rgba(238, 180, 75, 0.4);
    color: var(--color-tuscan-yellow, #EEB44B);
}

.pl-public-topbar__logout {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    padding: 7px 14px;
    border-radius: 4px;
    border: 1px solid rgba(26, 69, 104, 0.6);
    background: rgba(255, 255, 255, 0.02);
    color: var(--color-steel, #96acbb);
    text-decoration: none;
}
.pl-public-topbar__logout:hover {
    border-color: rgba(238, 180, 75, 0.35);
    color: var(--color-cream, #f4efdd);
    text-decoration: none;
}

/* Brand-only variant: a page that offers no public navigation at all (the token
   review page). It deliberately declares neither height nor padding — inheriting
   the base rule is what keeps the safe-area inset intact. Anything added here
   that touches the box must repeat the fallback pair above, in full. */
.pl-public-topbar--minimal {
    justify-content: flex-start;
}
/* The minimal bar's brand is a <span>, not an <a>, so it must not keep the
   anchor's hover affordance — dimming on hover with no cursor change and
   nothing to click reads as a broken link. */
.pl-public-topbar--minimal .pl-public-topbar__brand:hover {
    opacity: 1;
}

/* The authenticated five-item row needs roughly 796px laid out, so the bar stops
   fitting well above phone width. 880 matches the sibling .cp-topbar breakpoint
   in cms-public.css and keeps iPad portrait (768px) on a single line, which a
   640px rule would not. */
@media (max-width: 880px) {
    .pl-public-topbar {
        /* The env() term is repeated IN FULL here on purpose. This shorthand has
           the same specificity as the base rule and sits later in the file, so a
           plain `padding: 0 0.75rem` would win at every width at or below 880px
           and silently delete the notch inset on exactly the devices this
           breakpoint exists for. Fallback pair again, for the same reason. */
        padding: 0 0.75rem;
        padding: env(safe-area-inset-top, 0px) 0.75rem 0;
        gap: 0.5rem;
    }

    .pl-public-topbar__nav {
        gap: 8px;
    }

    .pl-public-topbar__ext,
    .pl-public-topbar__pill {
        display: none;
    }

    .pl-public-topbar__link {
        font-size: 12px;
    }

    .pl-public-topbar__signup {
        padding: 8px 12px;
    }

    .pl-public-topbar__login,
    .pl-public-topbar__logout {
        padding: 8px 10px;
    }
}

/* The last two things a phone can give up: the " Member Portal" suffix, and the
   Classes link — the brand anchor already points at the same page, so dropping
   it removes a duplicate, not a destination. */
@media (max-width: 480px) {
    .pl-public-topbar__wordmark {
        display: none;
    }

    .pl-public-topbar__link--catalog {
        display: none;
    }
}

/* When no sidebar (anonymous), the wrapper occupies the full viewport. */
.hub-main-wrapper--public { margin-left: 0; }

/* ──────────────────────────────────────────────────────────────
   Profile Settings — visibility-aware redesign
   ────────────────────────────────────────────────────────────── */

.pl-profile-edit { display: flex; flex-direction: column; gap: 1.25rem; }

/* Master "Listed/Hidden" panel */
.pl-profile-master {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    column-gap: 1.5rem;
    row-gap: 0.625rem;
    background: var(--hub-card-bg);
    border: 1px solid rgba(255,255,255,0.06);
    border-radius: 12px;
    padding: 1rem 1.25rem;
}
[data-theme="light"] .pl-profile-master { border-color: rgba(0,0,0,0.08); }
.pl-profile-master__copy { min-width: 0; }
.pl-profile-master__title { margin: 0 0 0.125rem; font-size: 1rem; font-weight: 700; color: var(--hub-text); }
.pl-profile-master__sub { margin: 0; font-size: 0.8125rem; color: var(--hub-text-muted); line-height: 1.45; }

.pl-profile-master__seg {
    display: inline-flex;
    align-items: stretch;
    justify-self: end;
    background: rgba(255,255,255,0.05);
    border: 1px solid rgba(255,255,255,0.1);
    border-radius: 999px;
    padding: 3px;
    gap: 2px;
}
[data-theme="light"] .pl-profile-master__seg {
    background: rgba(0,0,0,0.04);
    border-color: rgba(0,0,0,0.1);
}
.pl-profile-master__seg-input {
    position: absolute; opacity: 0; pointer-events: none; width: 0; height: 0;
}
.pl-profile-master__seg-btn {
    display: inline-flex; align-items: center; gap: 0.375rem;
    padding: 0.4375rem 0.875rem;
    border: 0;
    background: transparent;
    color: var(--hub-text-muted);
    font-size: 0.75rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.05em;
    border-radius: 999px;
    cursor: pointer;
    transition: background 0.18s, color 0.18s, box-shadow 0.18s;
    line-height: 1;
}
.pl-profile-master__seg-btn:hover:not(.pl-profile-master__seg-btn--active):not(:disabled) {
    color: var(--hub-text);
}
.pl-profile-master__seg-btn--active {
    background: var(--color-tuscan-yellow, #EEB44B);
    color: #1a1a2e;
    box-shadow: 0 1px 3px rgba(0,0,0,0.18);
}
.pl-profile-master__seg--locked .pl-profile-master__seg-btn { cursor: not-allowed; }
.pl-profile-master__seg--locked .pl-profile-master__seg-btn:not(.pl-profile-master__seg-btn--active) {
    opacity: 0.4;
}
.pl-profile-master__locked-note {
    grid-column: 1 / -1;
    margin: 0; font-size: 0.75rem; color: var(--hub-text-muted); line-height: 1.45;
}

@media (max-width: 560px) {
    .pl-profile-master { grid-template-columns: 1fr; }
    .pl-profile-master__seg { justify-self: start; }
}

/* Two-column grid */
.pl-profile-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 320px;
    gap: 1.5rem;
    align-items: start;
    margin-top: 0.5rem;
}
.pl-profile-edit__col { display: flex; flex-direction: column; gap: 1rem; }

@media (max-width: 900px) {
    .pl-profile-grid { grid-template-columns: 1fr; }
    .pl-profile-preview { order: -1; }
    .pl-profile-preview__sticky { position: static !important; }
}

/* Each row */
.pl-profile-row {
    background: var(--hub-card-bg);
    border: 1px solid rgba(255,255,255,0.06);
    border-radius: 10px;
    padding: 0.875rem 1rem;
    display: flex; flex-direction: column; gap: 0.4375rem;
}
[data-theme="light"] .pl-profile-row { border-color: rgba(0,0,0,0.08); }
.pl-profile-row__head {
    display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
}
.pl-profile-row__label {
    font-size: 0.8125rem; font-weight: 600; color: var(--hub-text);
    text-transform: uppercase; letter-spacing: 0.04em;
}
.pl-profile-row input[type="text"],
.pl-profile-row input[type="email"],
.pl-profile-row input[type="tel"],
.pl-profile-row input[type="url"],
.pl-profile-row select,
.pl-profile-row textarea {
    width: 100%;
    padding: 0.625rem 0.875rem;
    font-family: var(--font-body);
    font-size: 0.9375rem;
    font-weight: 300;
    color: var(--hub-text);
    background-color: var(--hub-input-bg);
    border: 1px solid var(--hub-input-border);
    border-radius: 6px;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.pl-profile-row textarea { resize: vertical; min-height: 96px; }

.pl-profile-row input:focus,
.pl-profile-row select:focus,
.pl-profile-row textarea:focus {
    outline: none;
    border-color: var(--color-tuscan-yellow);
    box-shadow: 0 0 0 3px rgba(238, 180, 75, 0.15);
}

.pl-profile-row input:disabled { opacity: 0.5; cursor: not-allowed; }

/* Visibility toggle pill */
.pl-vis-toggle {
    display: inline-flex; align-items: center; gap: 0.3125rem;
    padding: 3px 9px 3px 8px;
    border-radius: 999px;
    border: 1px solid currentColor;
    background: transparent;
    font-size: 0.6875rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.05em;
    cursor: pointer;
    transition: background 0.15s, color 0.15s, opacity 0.15s;
}
.pl-vis-toggle--on { color: #4ade80; background: rgba(74, 222, 128, 0.10); }
.pl-vis-toggle--on:hover { background: rgba(74, 222, 128, 0.18); }
.pl-vis-toggle--off { color: var(--hub-text-muted); background: transparent; }
.pl-vis-toggle--off:hover { background: rgba(255,255,255,0.05); }
.pl-vis-toggle--disabled { opacity: 0.4; cursor: not-allowed; }
[data-theme="light"] .pl-vis-toggle--on { color: #16a34a; background: rgba(22, 163, 74, 0.10); }

/* iOS-style toggle switch — applied to a checkbox <input class="hub-switch-input">.
   Reusable: any boolean form field can render as a switch by adding this class. */
.hub-switch-input {
    appearance: none; -webkit-appearance: none;
    flex: none; position: relative;
    width: 2.5rem; height: 1.375rem;
    border-radius: 999px;
    background: var(--hub-border);
    cursor: pointer;
    transition: background 0.15s ease;
    margin: 0;
}
.hub-switch-input::before {
    content: ""; position: absolute; top: 2px; left: 2px;
    width: 1.125rem; height: 1.125rem;
    border-radius: 50%;
    background: #fff;
    transition: transform 0.15s ease;
}
.hub-switch-input:checked { background: var(--hub-accent, #c46a1b); }
.hub-switch-input:checked::before { transform: translateX(1.125rem); }
.hub-switch-input:focus-visible { outline: 2px solid var(--hub-accent, #c46a1b); outline-offset: 2px; }
.hub-switch-input:disabled { opacity: 0.4; cursor: not-allowed; }

/* Always-shown badge */
.pl-vis-static {
    display: inline-flex; align-items: center; gap: 0.3125rem;
    padding: 3px 9px;
    font-size: 0.625rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.05em;
    color: var(--hub-text-muted);
}

/* Reassurance panel */
.pl-profile-never {
    margin-top: 0.5rem;
    padding: 0.875rem 1rem;
    background: rgba(255,255,255,0.025);
    border: 1px dashed rgba(255,255,255,0.14);
    border-radius: 10px;
}
[data-theme="light"] .pl-profile-never { background: rgba(0,0,0,0.025); border-color: rgba(0,0,0,0.14); }
.pl-profile-never__title {
    display: flex; align-items: center; gap: 0.4375rem;
    margin: 0 0 0.5rem;
    font-size: 0.75rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.05em;
    color: var(--hub-text-muted);
}
.pl-profile-never__list {
    margin: 0; padding-left: 1.25rem;
    font-size: 0.8125rem; color: var(--hub-text-muted);
    line-height: 1.7;
}

/* Live preview */
.pl-profile-preview__sticky { position: sticky; top: 1rem; }
.pl-profile-preview__heading {
    margin: 0 0 0.5rem;
    font-size: 0.6875rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.06em;
    color: var(--hub-text-muted);
}
.pl-profile-preview__card {
    background: var(--hub-card-bg);
    border: 1px solid rgba(255,255,255,0.08);
    border-radius: 12px;
    padding: 1.25rem 1rem;
    text-align: center;
    transition: opacity 0.18s;
}
[data-theme="light"] .pl-profile-preview__card { border-color: rgba(0,0,0,0.1); }
.pl-profile-preview__card--hidden {
    border-style: dashed;
    background: transparent;
}
.pl-profile-preview__hidden {
    display: flex; flex-direction: column; align-items: center; gap: 0.5rem;
    color: var(--hub-text-muted);
    padding: 1.5rem 0.5rem;
}
.pl-profile-preview__hidden p { margin: 0; font-size: 0.875rem; }
.pl-profile-preview__hidden-sub { font-size: 0.75rem !important; opacity: 0.7; }
.pl-profile-preview__avatar-wrap {
    display: flex; justify-content: center; margin-bottom: 0.75rem;
}
.pl-profile-preview__avatar {
    width: 84px; height: 84px;
    background: rgba(255,255,255,0.08);
    color: var(--hub-text);
    border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    font-size: 1.875rem; font-weight: 700;
}
.pl-profile-preview__avatar--photo { object-fit: cover; background: none; }
.pl-profile-preview__name { font-size: 1rem; font-weight: 700; color: var(--hub-text); }
.pl-profile-preview__meta {
    display: flex; flex-wrap: wrap; justify-content: center; gap: 0.375rem;
    margin: 0.5rem 0;
}
.pl-profile-preview__pill {
    display: inline-block;
    padding: 2px 9px;
    background: var(--color-tuscan-yellow, #EEB44B);
    color: #1a1a2e;
    font-size: 0.6875rem; font-weight: 700;
    border-radius: 999px;
    text-transform: uppercase; letter-spacing: 0.04em;
}
.pl-profile-preview__pill--soft {
    background: rgba(255,255,255,0.08);
    color: var(--hub-text-muted);
}
[data-theme="light"] .pl-profile-preview__pill--soft { background: rgba(0,0,0,0.06); }
.pl-profile-preview__about {
    margin: 0.625rem 0;
    font-size: 0.8125rem; color: var(--hub-text-muted); line-height: 1.5;
    text-align: left;
}
.pl-profile-preview__contact {
    margin-top: 0.75rem;
    display: flex; flex-direction: column; gap: 0.3125rem;
    text-align: left;
}
.pl-profile-preview__contact-row {
    display: flex; gap: 0.5rem; font-size: 0.8125rem;
}
.pl-profile-preview__contact-row > span:first-child {
    flex-shrink: 0; min-width: 56px;
    color: var(--hub-text-muted);
    font-size: 0.6875rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.04em;
    line-height: 1.45;
}
.pl-profile-preview__contact-row > span:last-child {
    color: var(--hub-text); word-break: break-word;
}
.pl-profile-preview__caption {
    margin: 0.5rem 0 0;
    font-size: 0.6875rem; color: var(--hub-text-muted); text-align: center;
}

.pl-profile-actionbar {
    margin-top: 0.5rem;
    display: flex; justify-content: flex-end; gap: 0.5rem;
}

/* ──────────────────────────────────────────────────────────────
   Floating Feedback button (mobile)
   ────────────────────────────────────────────────────────────── */
.hub-feedback-fab {
    display: none;
    position: fixed;
    right: calc(env(safe-area-inset-right, 0px) + 1rem);
    bottom: calc(env(safe-area-inset-bottom, 0px) + 1rem);
    width: 52px;
    height: 52px;
    border-radius: 50%;
    background: var(--color-tuscan-yellow, #EEB44B);
    color: #1a1a2e;
    align-items: center;
    justify-content: center;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.32), 0 2px 4px rgba(0, 0, 0, 0.18);
    z-index: 95;
    text-decoration: none;
    transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}

.hub-feedback-fab:hover,
.hub-feedback-fab:focus-visible {
    background: #f5ca6e;
    transform: translateY(-1px);
    box-shadow: 0 10px 22px rgba(0, 0, 0, 0.35), 0 3px 6px rgba(0, 0, 0, 0.2);
    text-decoration: none;
}

.hub-feedback-fab.active {
    background: #1a1a2e;
    color: var(--color-tuscan-yellow, #EEB44B);
}

@media (max-width: 768px) {
    .hub-feedback-fab { display: inline-flex; }
    /* Hide the in-sidebar feedback link on mobile — the FAB replaces it. */
    .hub-sidebar__link--feedback { display: none; }
    /* Clear the FAB's footprint (52px + 1rem offset) so it never sits on
       top of the last form field or button on the page. */
    .hub-content,
    body.classes-portal .cp-page {
        padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 6rem);
    }
}

/* ========================================
   Admin table toolkit
   ======================================== */
.admin-toolbar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
    margin-bottom: 0.75rem;
}

.admin-filters {
    display: flex;
    gap: 0.375rem;
    flex-wrap: wrap;
    align-items: center;
    margin-bottom: 0.75rem;
}

/* Thin vertical rule separating the exclusive status pills from the orthogonal
   "My Classes" toggle. Hidden on phones (below) where the flex-wrap already
   provides visual separation and the divider can orphan at a line edge. */
.pl-filter-divider {
    width: 1px;
    height: 1.25rem;
    background: var(--hub-border);
}

@media (max-width: 640px) {
    .pl-filter-divider {
        display: none;
    }
}

.admin-table-wrap {
    border: 1px solid var(--hub-border);
    border-radius: 8px;
    overflow: hidden;
}

.admin-table-wrap table {
    width: 100%;
    border-collapse: collapse;
}

.admin-table-wrap thead {
    background: rgba(0, 0, 0, 0.06);
}

[data-theme="light"] .admin-table-wrap thead,
html:not(.dark) .admin-table-wrap thead {
    background: rgba(0, 0, 0, 0.03);
}

.admin-table-wrap thead th {
    text-align: left;
    padding: 0.6rem 0.75rem;
    font-weight: 600;
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--hub-text-muted);
    border-bottom: 1px solid var(--hub-border);
}

.admin-table-wrap thead th a {
    color: inherit;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.admin-table-wrap thead th a:hover {
    color: var(--hub-text);
    text-decoration: none;
}

.admin-table-wrap tbody td {
    padding: 0.6rem 0.75rem;
    font-size: 0.875rem;
}

.admin-table-wrap tbody tr {
    border-bottom: 1px solid var(--hub-border);
}

/* Zebra striping for readability — subtle, theme-aware. */
.admin-table-wrap tbody tr:nth-child(even) {
    background: rgba(255, 255, 255, 0.025);
}

[data-theme="light"] .admin-table-wrap tbody tr:nth-child(even),
html:not(.dark) .admin-table-wrap tbody tr:nth-child(even) {
    background: rgba(0, 0, 0, 0.025);
}

.admin-table-wrap tbody tr:last-child {
    border-bottom: none;
}

/* Hover wins over stripes — defined last so equal-specificity source order favors it. */
.admin-table-wrap tbody tr:hover {
    background: rgba(238, 180, 75, 0.07);
}

.admin-table-wrap .admin-actions {
    display: flex;
    gap: 0.375rem;
    justify-content: flex-end;
    flex-wrap: nowrap;
    white-space: nowrap;
}

/* Row-action button strips (table actions, "needs your attention" rows): every
   button shares a min-width so columns line up across rows regardless of label
   length (Approve/Unapprove/Edit/Delete/Review). */
.admin-actions .hub-btn,
.pl-row-actions .hub-btn {
    min-width: 6rem;
    text-align: center;
}
.pl-row-actions {
    display: inline-flex;
    gap: 0.375rem;
    align-items: center;
}

/* Guild-tagging per-row category picker — theme-aware input tokens so the
   select and its native option popup stay legible on both themes (FRONTEND
   Rule 13). */
.pl-guild-tag-select {
    width: 100%;
    max-width: 22rem;
    padding: 0.4rem 0.6rem;
    font-family: var(--font-body);
    font-size: 0.875rem;
    color: var(--hub-text);
    background-color: var(--hub-input-bg);
    border: 1px solid var(--hub-input-border);
    border-radius: 6px;
}

.pl-guild-tag-select:focus {
    outline: none;
    border-color: var(--color-tuscan-yellow);
    box-shadow: 0 0 0 3px rgba(238, 180, 75, 0.15);
}

.pl-guild-tag-select option {
    background: var(--hub-input-bg);
    color: var(--hub-text);
}

.admin-table-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0.75rem 1rem;
    border: 1px solid var(--hub-border);
    border-top: none;
    border-radius: 0 0 8px 8px;
    background: var(--hub-card-bg);
    font-size: 0.8rem;
    color: var(--hub-text-muted);
}

.admin-table-footer nav {
    display: flex;
    align-items: center;
    gap: 0.25rem;
}

/* Classes-admin Overview: section titles — accent bar + stronger weight so
   headings read as section headers, not body text. */
.cms-overview .overview-title {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    margin: 0 0 0.9rem;
    padding-left: 0.6rem;
    border-left: 3px solid var(--color-tuscan-yellow, #EEB44B);
    font-weight: 700;
    font-size: 1rem;
    line-height: 1.25;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--hub-text);
}

.cms-overview .overview-title__count {
    color: var(--hub-text-muted);
    font-weight: 600;
    font-size: 0.9em;
}

/* Subordinate heading for a block nested inside an Overview card (e.g. Recent
   sign-ups within "At a glance"). Lighter than .overview-title to signal nesting. */
.cms-overview .overview-subtitle {
    margin: 0;
    font-size: 0.85rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--hub-text);
}

/* Merged "Needs Attention" card — the classes admin Overview and the instructor Overview.
   One card carries several review queues as labeled groups. A group with no rows renders
   nothing at all (no heading, no "nothing waiting" line), and when every group is empty the
   whole card collapses to .pl-attention-clear: one quiet strip the height of the Waitlists
   strip, instead of three tall empty cards.

   The adjacency selector this rule used to carry (.pl-attention-group + .pl-attention-group)
   gave the FIRST group no rule of its own, so the card title ran straight into the first
   group's heading with nothing between them — "Needs Attention (3)" butting up against
   "Waiting on Your Review". Dropped, so every group is separated from whatever is above it
   (ruling 20). Scoped to .cms-overview, which is where every .pl-attention-group in the app
   already lives: both Overview pages wrap theirs in one. */
.cms-overview .pl-attention-group {
    margin-top: 0.9rem;
    padding-top: 0.9rem;
    border-top: 1px solid var(--hub-border);
}

.cms-overview .pl-attention-group__title {
    margin: 0 0 0.6rem;
}

.pl-attention-clear {
    padding: 0.75rem 1rem;
}

.pl-attention-clear__text {
    color: var(--hub-text-muted);
    font-size: 0.875rem;
}

/* Topbar notification bell — a plain link to the Notifications page (no dropdown). */
.pl-bell__btn { position: relative; background: none; border: none; color: var(--hub-text); cursor: pointer; padding: 0.4rem; border-radius: 6px; text-decoration: none; }
.pl-bell__btn:hover { background: rgba(255,255,255,0.06); }
[data-theme="light"] .pl-bell__btn:hover { background: rgba(0,0,0,0.06); }
.pl-bell__badge { position: absolute; top: 0; right: 0; min-width: 16px; height: 16px; padding: 0 4px; border-radius: 8px; background: #ef4444; color: #fff; font-size: 0.625rem; line-height: 16px; text-align: center; font-weight: 700; }

/* Notifications page (hub/notifications.html) — responsive header + pager. */
.pl-notes__header { display: flex; justify-content: space-between; align-items: center; gap: 1rem; flex-wrap: wrap; margin-bottom: 1.5rem; }
.pl-notes__actions { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; }
.pl-notes__pager { display: flex; flex-wrap: wrap; gap: 0.75rem; justify-content: center; align-items: center; margin-top: 1.5rem; }

/* Notification rows. */
.pl-note { border-bottom: 1px solid var(--hub-border); }
.pl-note__btn { display: flex; flex-direction: column; gap: 0.15rem; width: 100%; min-width: 0; text-align: left; background: none; border: none; padding: 0.75rem 1rem; cursor: pointer; color: var(--hub-text); }
.pl-note__btn:hover { background: rgba(255,255,255,0.04); }
[data-theme="light"] .pl-note__btn:hover { background: rgba(0,0,0,0.04); }
.pl-note--unread .pl-note__btn { background: rgba(238,180,75,0.08); }
[data-theme="light"] .pl-note--unread .pl-note__btn { background: rgba(238,180,75,0.16); }
.pl-note__title { font-weight: 600; font-size: 0.875rem; overflow-wrap: anywhere; }
.pl-note__body { font-size: 0.8125rem; color: var(--hub-text-muted); overflow-wrap: anywhere; }
.pl-note__time { font-size: 0.6875rem; color: var(--hub-text-muted); }

/* ── Guild detail page redesign (pl-guild-*) ──────────────────────────── */
.pl-guild-hero { position: relative; min-height: clamp(220px, 32vw, 380px); border-radius: 8px; overflow: hidden; margin-bottom: 1.5rem; display: flex; align-items: flex-end; }
.pl-guild-hero__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.pl-guild-hero__overlay { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(9,46,76,0) 0%, rgba(9,46,76,0.85) 100%); }
.pl-guild-hero--noimg { background: linear-gradient(120deg, var(--hub-hero-from) 0%, var(--hub-hero-mid) 46%, var(--hub-hero-to) 100%); }
.pl-guild-hero__content { position: relative; z-index: 1; padding: 1.5rem; color: #F4EFDD; }
.pl-guild-hero__title { font-family: Lato, sans-serif; font-weight: 900; font-size: clamp(1.75rem, 4vw, 2.75rem); margin: 0; color: #F4EFDD; }
[data-theme="light"] .pl-guild-hero--noimg .pl-guild-hero__title { color: var(--hub-text); }
[data-theme="light"] .pl-guild-hero--noimg .pl-guild-hero__lead { color: var(--hub-text-muted); opacity: 1; }
.pl-guild-hero__lead { font-size: 0.9375rem; opacity: 0.9; margin-top: 0.25rem; }
/* Hero placement adjuster toolbar (x-show target — display lives in the class, never inline, per FRONTEND.md Rule 12). */
.pl-hero-adjust { display: flex; align-items: center; gap: 1rem; }
.pl-guild-grid { display: grid; grid-template-columns: 1fr; gap: 1.5rem; }
.pl-guild-grid aside { display: flex; flex-direction: column; gap: 1.5rem; }
@media (min-width: 1024px) { .pl-guild-grid { grid-template-columns: 1fr 340px; } }
.pl-guild-section { padding: 1.25rem 0; border-top: 1px solid var(--hub-border); }
.pl-guild-section:first-child { border-top: none; padding-top: 0; }
.pl-guild-section__h2 { font-family: Lato, sans-serif; font-weight: 700; font-size: 1.375rem; margin: 0 0 0.75rem; }
/* Wiki how-it-works guides — a table of contents plus anchored article sections. */
.pl-wiki-toc { border: 1px solid var(--hub-border); border-radius: 8px; background: var(--hub-surface); padding: 1rem 1.25rem; margin-bottom: 1.5rem; }
.pl-wiki-toc .hub-detail-label { margin: 0 0 0.5rem; }
.pl-wiki-toc ul { list-style: none; margin: 0; padding: 0; columns: 2; column-gap: 1.5rem; }
@media (max-width: 640px) { .pl-wiki-toc ul { columns: 1; } }
.pl-wiki-toc li { margin: 0 0 0.35rem; break-inside: avoid; }
.pl-wiki-toc a { color: var(--color-tuscan-yellow); text-decoration: none; }
.pl-wiki-toc a:hover { text-decoration: underline; }
.pl-wiki-article { scroll-margin-top: 1rem; }

/* Help-profile prose: committed screenshots + anchor jumps that clear the topbar.
   Scoped to .pl-md--help — the base .pl-md deliberately has no img rule. */
.pl-md--help img { max-width: 100%; height: auto; border: 1px solid var(--hub-border); border-radius: 8px; margin: 0.75rem 0; }
/* Video walkthroughs (Loom / privacy-mode YouTube) — the sanitizer only lets the two
   players through, so a bare responsive 16:9 rule covers every embed a guide can hold. */
.pl-md--help iframe { width: 100%; aspect-ratio: 16 / 9; border: 1px solid var(--hub-border); border-radius: 8px; margin: 0.75rem 0; display: block; }
.pl-md--help [id] { scroll-margin-top: 1rem; }
/* Guide headings run bigger than the base .pl-md ladder — Lato display treatment so
   sections read as real landmarks inside a long guide (h4+ keep the base sizes). */
.pl-md--help h2 {
    font-family: var(--font-heading);
    font-size: 1.55rem;
    font-weight: 700;
    letter-spacing: -0.015em;
    margin-top: 2.4rem;
    padding-bottom: 0.35rem;
}
.pl-md--help h3 {
    font-family: var(--font-heading);
    font-size: 1.25rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    margin-top: 1.8rem;
}

/* Confluence-style callouts (help profile only) — `!!! note` / info / tip / warning.
   Bordered card on the surface layer with a colored left edge + title row. All
   colors are theme-aware tokens: --hub-blue and --hub-link swap under
   [data-theme="light"], and --pl-sync-synced is the existing theme-aware green. */
.pl-md--help .admonition { margin: 1rem 0; padding: 0.75rem 1rem; background: var(--hub-surface); border: 1px solid var(--hub-border); border-left: 4px solid var(--hub-blue); border-radius: 8px; }
.pl-md--help .admonition > p { margin: 0 0 0.5rem; }
.pl-md--help .admonition > p:last-child { margin-bottom: 0; }
.pl-md--help .admonition .admonition-title { margin: 0 0 0.25rem; font-weight: 700; font-size: 0.9rem; color: var(--hub-blue); }
.pl-md--help .admonition.tip { border-left-color: var(--pl-sync-synced); }
.pl-md--help .admonition.tip .admonition-title { color: var(--pl-sync-synced); }
.pl-md--help .admonition.warning { border-left-color: var(--color-tuscan-yellow); }
.pl-md--help .admonition.warning .admonition-title { color: var(--hub-link); }

/* Help center — landing grid, badges, breadcrumbs, rows, article chrome, search. */
.pl-help-searchcard { margin-bottom: 1.5rem; padding: 0.75rem 1rem; }

/* ── Help landing hero — title + intro lead + the search bar as the centerpiece.
   Reuses the .pl-guild-hero backdrop machinery (banner + overlay, or the theme-aware
   --noimg gradient); this block only centers the content and styles the search. ── */
.pl-help-hero { align-items: center; justify-content: center; text-align: center; }
/* Content sits mid-hero (not bottom-aligned like guild pages), so deepen the overlay
   across the whole banner to keep the cream copy readable over any photo. */
.pl-help-hero .pl-guild-hero__overlay { background: linear-gradient(180deg, rgba(9, 46, 76, 0.55) 0%, rgba(9, 46, 76, 0.85) 100%); }
.pl-help-hero .pl-guild-hero__content {
    width: 100%;
    max-width: 680px;
    padding: 2.75rem 1.5rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.75rem;
}
.pl-help-hero__lead { margin: 0; max-width: 58ch; }
.pl-help-hero__lead p { margin: 0 0 0.35rem; color: inherit; }
.pl-help-hero__lead p:last-child { margin-bottom: 0; }
.pl-help-hero__lead a { color: var(--color-tuscan-yellow); }
.pl-help-hero__search { display: flex; gap: 0.5rem; width: 100%; max-width: 560px; margin-top: 0.5rem; }
.pl-help-hero__input {
    flex: 1;
    min-width: 0;
    padding: 0.8rem 1.1rem;
    font-size: 1rem;
    font-family: var(--font-body);
    border: 1px solid var(--hub-input-border);
    border-radius: 8px;
    background: var(--hub-input-bg);
    color: var(--hub-text);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
}
.pl-help-hero__input:focus { outline: 2px solid var(--hub-blue); outline-offset: 1px; }
[data-theme="light"] .pl-help-hero__input { box-shadow: 0 4px 14px rgba(0, 0, 0, 0.12); }
.pl-help-hero__admin {
    position: absolute;
    top: 0.75rem;
    right: 0.75rem;
    z-index: 2;
    display: flex;
    gap: 0.5rem;
    align-items: center;
    flex-wrap: wrap;
    justify-content: flex-end;
}
/* The intro's admonition tail (the seeded tip) sits below the hero in normal flow. */
.pl-help-intro-rest { margin-bottom: 1.5rem; }
@media (max-width: 640px) {
    .pl-help-hero__search { flex-direction: column; }
    .pl-help-hero__search .pl-btn { width: 100%; }
}
/* Landing category sections — every published guide is linked right on the card
   (Confluence-space style). auto-fit: a lone card in its audience group stretches
   to a full-width row; the member group packs two-up. */
.pl-helpcat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1rem; }
.pl-helpcat-card { display: flex; flex-direction: column; gap: 0.5rem; padding: 1rem 1.25rem; background: var(--hub-card-bg); border: 1px solid var(--hub-border); border-radius: 8px; color: var(--hub-text); }
.pl-helpcat-card__head { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
.pl-helpcat-card__name { font-weight: 700; color: var(--hub-text); text-decoration: none; }
.pl-helpcat-card__name:hover { color: var(--hub-link); }
.pl-helpcat-card__desc { margin: 0; color: var(--hub-text-muted); font-size: 0.875rem; }
.pl-helpcat-card__guides { list-style: none; margin: 0.25rem 0 0; padding: 0; }
.pl-helpcat-card__guides li + li { border-top: 1px solid var(--hub-border); }
.pl-helpcat-card__guides a { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; padding: 0.5rem 0; color: var(--hub-link); text-decoration: none; font-size: 0.9rem; }
.pl-helpcat-card__guides a:hover { color: var(--hub-link-hover); text-decoration: underline; }
.pl-helpcat-card__chev { color: var(--hub-text-muted); font-size: 1rem; line-height: 1; }
.pl-helpcat-card__guides a:hover .pl-helpcat-card__chev { color: var(--hub-link-hover); }
.pl-helpcat-card__count { margin-top: auto; padding-top: 0.25rem; color: var(--hub-text-muted); font-size: 0.8rem; }
.pl-help-badge { display: inline-block; padding: 0.1rem 0.5rem; border: 1px solid var(--hub-border); border-radius: 999px; background: var(--hub-surface); color: var(--hub-text-muted); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.04em; white-space: nowrap; }
/* Audience color coding — subtle tinted chips per HelpCategory.Audience value (the
   plain badge above stays neutral for Draft and category-name chips). Tints derive
   from theme tokens via color-mix, so both Obsidian and Slate stay legible. */
.pl-help-badge--member {
    color: var(--hub-blue);
    border-color: color-mix(in srgb, var(--hub-blue) 40%, transparent);
    background: color-mix(in srgb, var(--hub-blue) 12%, transparent);
}
.pl-help-badge--instructor {
    color: var(--pl-sync-synced);
    border-color: color-mix(in srgb, var(--pl-sync-synced) 40%, transparent);
    background: color-mix(in srgb, var(--pl-sync-synced) 12%, transparent);
}
.pl-help-badge--guild_lead {
    color: var(--hub-link);
    border-color: color-mix(in srgb, var(--color-tuscan-yellow) 45%, transparent);
    background: color-mix(in srgb, var(--color-tuscan-yellow) 14%, transparent);
}
.pl-help-badge--admin {
    color: var(--pl-help-admin);
    border-color: color-mix(in srgb, var(--pl-help-admin) 40%, transparent);
    background: color-mix(in srgb, var(--pl-help-admin) 12%, transparent);
}
.pl-help-badge--developer {
    color: var(--pl-help-developer);
    border-color: color-mix(in srgb, var(--pl-help-developer) 40%, transparent);
    background: color-mix(in srgb, var(--pl-help-developer) 12%, transparent);
}
.pl-help-cat-eyebrow { margin-bottom: 0.5rem; }
.pl-help-breadcrumbs { margin-bottom: 0.75rem; font-size: 0.875rem; color: var(--hub-text-muted); }
.pl-help-breadcrumbs a { color: var(--hub-text-muted); text-decoration: none; }
.pl-help-breadcrumbs a:hover { color: var(--color-tuscan-yellow); }
.pl-help-linklist { list-style: none; margin: 0; padding: 0; }
.pl-help-linklist li { margin: 0 0 0.5rem; }
.pl-help-linklist a { display: inline-block; margin-right: 0.5rem; color: var(--color-tuscan-yellow); text-decoration: none; }
.pl-help-linklist a:hover { text-decoration: underline; }
.pl-help-row { display: flex; align-items: center; gap: 1rem; padding: 0.75rem 0.25rem; border-bottom: 1px solid var(--hub-border); text-decoration: none; color: var(--hub-text); }
.pl-help-row:last-child { border-bottom: none; }
.pl-help-row__body { flex: 1; min-width: 0; }
.pl-help-row__title { display: block; color: var(--color-tuscan-yellow); font-weight: 600; }
.pl-help-row:hover .pl-help-row__title { text-decoration: underline; }
.pl-help-row__lead { display: block; font-size: 0.875rem; margin-top: 0.25rem; }
.pl-help-row__chevron { color: var(--hub-text-muted); font-size: 1.25rem; }
.pl-help-draftbanner { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 1.5rem; padding: 0.5rem 1rem; border: 1px solid var(--hub-border); border-radius: 8px; background: var(--hub-surface); color: var(--hub-text-muted); font-size: 0.875rem; }
/* Related guides — equal-height compact cards: title, colored audience chip, one-line
   lead (clamped). Grid rows stretch, so a lead-less card still matches its neighbors. */
.pl-help-relatedgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 0.75rem; }
.pl-help-relatedcard { display: flex; flex-direction: column; gap: 0.4rem; align-items: flex-start; padding: 0.85rem 1rem; background: var(--hub-card-bg); border: 1px solid var(--hub-border); border-radius: 8px; text-decoration: none; color: var(--hub-text); transition: border-color 0.15s ease, background 0.15s ease; }
.pl-help-relatedcard:hover { border-color: var(--color-tuscan-yellow); background: var(--hub-surface); }
.pl-help-relatedcard:hover .pl-help-relatedcard__title { color: var(--hub-link); }
.pl-help-relatedcard__title { font-weight: 600; }
.pl-help-relatedcard__lead {
    color: var(--hub-text-muted);
    font-size: 0.85rem;
    line-height: 1.4;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
/* Docs-style pagination footer — hairline top rule, Previous left / Next pinned to the
   right column even when it's the only side; each cell is label-over-title. */
.pl-help-prevnext { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; margin-top: 2rem; padding-top: 1.25rem; border-top: 1px solid var(--hub-border); }
.pl-help-prevnext__link { display: flex; flex-direction: column; gap: 0.25rem; padding: 0.75rem 1rem; border: 1px solid var(--hub-border); border-radius: 8px; background: var(--hub-card-bg); text-decoration: none; color: var(--hub-text); transition: border-color 0.15s ease; }
.pl-help-prevnext__link:hover { border-color: var(--color-tuscan-yellow); }
.pl-help-prevnext__link:hover .pl-help-prevnext__title { color: var(--hub-link); }
.pl-help-prevnext__link--prev { grid-column: 1; align-items: flex-start; text-align: left; }
.pl-help-prevnext__link--next { grid-column: 2; align-items: flex-end; text-align: right; }
.pl-help-prevnext__label { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--hub-text-muted); }
.pl-help-prevnext__title { font-weight: 600; }
@media (max-width: 640px) {
    .pl-help-prevnext { grid-template-columns: 1fr; }
    .pl-help-prevnext__link--prev, .pl-help-prevnext__link--next { grid-column: auto; }
}
.pl-help-asidelist { list-style: none; margin: 0; padding: 0; }
.pl-help-asidelist li { margin: 0 0 0.5rem; }
.pl-help-asidelist a { color: var(--color-tuscan-yellow); text-decoration: none; }
.pl-help-asidelist a:hover { text-decoration: underline; }
.pl-help-searchcount { margin: 0 0 1rem; font-size: 0.875rem; }
.pl-help-result { margin-bottom: 1rem; }
.pl-help-result__title { display: inline-block; color: var(--color-tuscan-yellow); font-weight: 700; text-decoration: none; margin-right: 0.5rem; }
.pl-help-result__title:hover { text-decoration: underline; }
.pl-help-result__badges { display: inline-flex; gap: 0.5rem; vertical-align: middle; }
.pl-help-result__snippet { margin: 0.5rem 0 0; color: var(--hub-text-muted); font-size: 0.9rem; }
mark { background: color-mix(in srgb, var(--color-tuscan-yellow) 30%, transparent); color: inherit; border-radius: 3px; }

.pl-guild-video { position: relative; aspect-ratio: 16/9; border-radius: 6px; overflow: hidden; background: #000; }
.pl-guild-video iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* Linked video card — Instagram and Facebook, which we never embed (no third-party script
   on a member page), so the video is offered as a card that opens on their site. Mirrored
   in cms-public.css with that surface's tokens for the public class page. */
.pl-video-card { display: flex; flex-direction: column; gap: 0.25rem; padding: 0.75rem 1rem; background: var(--hub-card-bg); border: 1px solid var(--hub-border); border-radius: 8px; color: var(--hub-text); text-decoration: none; transition: border-color 0.15s ease, background 0.15s ease; }
.pl-video-card:hover { border-color: var(--color-tuscan-yellow); background: var(--hub-surface); text-decoration: none; }
.pl-video-card__provider { font-size: 0.75rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--color-tuscan-yellow); }
.pl-video-card__title { font-weight: 700; }
.pl-video-card__hint { font-size: 0.8125rem; color: var(--hub-text-muted); word-break: break-all; }
.pl-guild-gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 0.5rem; }
.pl-guild-gallery__item { aspect-ratio: 1; border-radius: 6px; overflow: hidden; cursor: pointer; border: none; padding: 0; background: none; }
.pl-guild-gallery__item img { width: 100%; height: 100%; object-fit: cover; }
.pl-guild-lightbox { position: fixed; inset: 0; background: rgba(0,0,0,0.9); display: flex; align-items: center; justify-content: center; z-index: 100; }
.pl-guild-lightbox img { max-width: 90vw; max-height: 90vh; border-radius: 6px; }

/* Space & Org Info — annotated floor plan / map. Reuses .pl-guild-lightbox for zoom. */
.pl-org-map { margin: 0; }
.pl-org-map__btn { display: block; width: 100%; padding: 0; border: 1px solid var(--hub-border); border-radius: 8px; overflow: hidden; background: var(--hub-surface); cursor: zoom-in; position: relative; }
.pl-org-map__btn img { display: block; width: 100%; height: auto; }
.pl-org-map__zoom { position: absolute; bottom: 0.75rem; right: 0.75rem; display: inline-flex; align-items: center; gap: 0.35rem; padding: 0.35rem 0.6rem; border-radius: 6px; background: rgba(0,0,0,0.6); color: #F4EFDD; font-size: 0.75rem; }
.pl-org-map__caption { margin: 0.6rem 0 0; color: var(--hub-text-muted); font-size: 0.85rem; }
.pl-org-map--empty { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 0; padding: 2rem 1.25rem; border: 1px dashed var(--hub-border); border-radius: 8px; background: var(--hub-surface); color: var(--hub-text-muted); }

.pl-guild-faq__q { font-weight: 600; cursor: pointer; padding: 0.75rem 0; border-top: 1px solid var(--hub-border); }
.pl-guild-faq__a { padding-bottom: 0.75rem; color: var(--hub-text-muted); }
.pl-guild-roster { display: flex; flex-direction: column; gap: 0.5rem; }
.pl-guild-links a { display: block; padding: 0.5rem 0; color: var(--color-tuscan-yellow); }

/* Rendered-Markdown body (guild meeting notes + Help page guides). Theme-tokened via
   --hub-* so it reads right in light and dark; scoped to .pl-md so nothing else shifts. */
.pl-md { color: var(--hub-text); line-height: 1.65; }
.pl-md p { margin: 0 0 0.85rem; }
.pl-md p:last-child { margin-bottom: 0; }
/* Descending heading hierarchy so subheadings inside a guide read as distinct levels. */
.pl-md h1, .pl-md h2, .pl-md h3, .pl-md h4, .pl-md h5, .pl-md h6 {
    color: var(--hub-text); font-weight: 700; line-height: 1.25;
    margin: 1.6rem 0 0.6rem;
}
.pl-md > :first-child { margin-top: 0; }
.pl-md h1 { font-size: 1.6rem; letter-spacing: -0.01em; }
.pl-md h2 { font-size: 1.35rem; letter-spacing: -0.01em; padding-bottom: 0.25rem; border-bottom: 1px solid var(--hub-border); }
.pl-md h3 { font-size: 1.15rem; }
.pl-md h4 { font-size: 1.02rem; }
.pl-md h5 { font-size: 0.9rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--hub-text-muted); }
.pl-md h6 { font-size: 0.85rem; font-weight: 600; color: var(--hub-text-muted); }
.pl-md ul, .pl-md ol { margin: 0 0 0.85rem; padding-left: 1.5rem; }
.pl-md li { margin-bottom: 0.3rem; }
.pl-md li > ul, .pl-md li > ol { margin: 0.3rem 0 0; }
.pl-md a { color: var(--color-tuscan-yellow); text-decoration: underline; }
.pl-md hr { border: 0; border-top: 1px solid var(--hub-border); margin: 1.5rem 0; }
.pl-md code { background: var(--hub-surface); padding: 0.1rem 0.35rem; border-radius: 4px; font-size: 0.9em; }
.pl-md pre { background: var(--hub-surface); padding: 0.75rem; border-radius: 6px; overflow-x: auto; margin: 0 0 0.85rem; }
.pl-md pre code { background: none; padding: 0; }
.pl-md blockquote { margin: 0 0 0.85rem; padding: 0.4rem 0 0.4rem 1rem; border-left: 3px solid var(--color-tuscan-yellow); background: var(--hub-surface); color: var(--hub-text-muted); border-radius: 0 4px 4px 0; }
.pl-md blockquote p:last-child { margin-bottom: 0; }
/* Tables: bordered, striped header, and horizontally scrollable when they outgrow the column. */
.pl-md table {
    display: block; width: max-content; max-width: 100%; overflow-x: auto;
    border-collapse: collapse; margin: 0 0 0.85rem; font-size: 0.95rem;
}
.pl-md th, .pl-md td { border: 1px solid var(--hub-border); padding: 0.45rem 0.7rem; text-align: left; vertical-align: top; }
.pl-md th { background: var(--hub-surface); font-weight: 600; color: var(--hub-text); }
.pl-md tbody tr:nth-child(even) td { background: var(--hub-surface); }

/* Orientation slot booking table. Layout lives in classes (not inline) so Alpine's
   x-show — which strips inline `display` when it reveals a row — can't break the columns. */
.pl-orient-slots__head,
.pl-orient-slots__row { display: flex; align-items: center; gap: 1rem; }
.pl-orient-slots__head {
    padding: 0 0 0.4rem;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--hub-text-muted);
}
.pl-orient-slots__row { padding: 0.55rem 0; border-top: 1px solid var(--hub-border); }
.pl-orient-slots__date { flex: 0 0 6rem; font-weight: 500; }
.pl-orient-slots__time { flex: 1; color: var(--hub-text-muted); font-size: 0.9rem; }
.pl-orient-slots__action { flex: 0 0 7rem; text-align: right; }
.pl-orient-slots__action .hub-btn { width: 100%; }
.pl-orient-slots__pager { display: flex; align-items: center; gap: 0.75rem; margin-top: 0.75rem; }
.pl-orient-slots__with { flex: 1; display: flex; align-items: center; gap: 0.4rem; min-width: 0; font-size: 0.9rem; }
@media (max-width: 640px) {
    .pl-orient-slots__row { flex-wrap: wrap; }
    .pl-orient-slots__with { flex-basis: 100%; }
}

/* Small orienter avatar chip ("with Bob") — theme tokens, initials fallback */
.pl-orient-avatar {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    object-fit: cover;
    flex: 0 0 auto;
}
.pl-orient-avatar--initials {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--hub-surface);
    color: var(--hub-text-muted);
    font-size: 0.65rem;
    font-weight: 700;
    text-transform: uppercase;
}

/* Orientations tab — hours rows, the All Orientation Hours overview, Upcoming Slots card */
.pl-hours-rows { display: flex; flex-direction: column; gap: 0.75rem; }
.pl-orient-overview__group { padding: 0.75rem 0; border-top: 1px solid var(--hub-border); }
.pl-orient-overview__person { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.pl-orient-overview__rules {
    list-style: none;
    padding: 0.4rem 0 0;
    margin: 0;
    font-size: 0.9rem;
    color: var(--hub-text);
}
.pl-slot-admin__row {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
    padding: 0.55rem 0;
    border-top: 1px solid var(--hub-border);
}
.pl-slot-admin__when { font-weight: 500; }
.pl-slot-admin__with { display: flex; align-items: center; gap: 0.4rem; flex: 1; min-width: 140px; }
.pl-slot-admin__seats { color: var(--hub-text-muted); font-size: 0.85rem; }
.pl-slot-admin__source { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.04em; }

/* Add A Slot date input — Rule 14 dark-mode picker icon */
.pl-slot-date::-webkit-calendar-picker-indicator { filter: invert(1); cursor: pointer; }
[data-theme="light"] .pl-slot-date::-webkit-calendar-picker-indicator { filter: none; }

/* "Post your hours" nudge banner on the orientations dashboard */
.pl-hours-nudge { padding: 0.9rem 1.5rem; margin-bottom: 1.5rem; border-left: 3px solid var(--color-tuscan-yellow); }
.pl-hours-nudge a { color: var(--color-tuscan-yellow); }

/* ============================================================
   Skills directory — filter bar, chips, commission badge, editor
   ============================================================ */

/* Member directory filters */
.pl-directory-filters {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 0.75rem;
    margin-bottom: 1.5rem;
}
.pl-filter-field { display: flex; flex-direction: column; gap: 0.25rem; }
.pl-filter-label { font-size: 0.75rem; color: var(--hub-text-muted); }
.pl-filter-control {
    background: var(--hub-input-bg);
    color: var(--hub-text);
    border: 1px solid var(--hub-input-border);
    border-radius: 6px;
    padding: 0.45rem 0.75rem;
    font-size: 0.875rem;
}
.pl-filter-control option { background: var(--hub-elevated); color: var(--hub-text); }
.pl-filter-checkbox { display: inline-flex; align-items: center; gap: 0.4rem; font-size: 0.875rem; color: var(--hub-text); }

/* Skill chips */
.pl-skill-chips { display: flex; flex-wrap: wrap; gap: 0.35rem; margin-top: 0.6rem; }
.pl-skill-chip {
    display: inline-flex; align-items: center; gap: 0.35rem;
    background: var(--hub-surface); color: var(--hub-text);
    border: 1px solid var(--hub-input-border);
    border-radius: 12px; padding: 2px 10px; font-size: 0.8125rem;
}
.pl-skill-chip__years { color: var(--hub-text-muted); font-size: 0.75rem; }
.pl-skill-chip__pending {
    color: var(--hub-text-muted); font-size: 0.7rem; font-style: italic;
    border: 1px solid var(--hub-input-border); border-radius: 8px; padding: 0 6px;
}

/* Open for commissions */
.pl-commission { margin-top: 0.75rem; }
.pl-commission__badge {
    display: inline-flex; align-items: center;
    background: rgba(238, 180, 75, 0.14); color: var(--color-tuscan-yellow);
    border: 1px solid rgba(238, 180, 75, 0.35);
    border-radius: 12px; padding: 2px 10px; font-size: 0.8125rem; font-weight: 700;
}
.pl-commission__note { margin: 0.4rem 0 0; font-size: 0.85rem; color: var(--hub-text-muted); }

/* Skill editor (profile settings) */
.pl-skill-editor { display: flex; flex-direction: column; gap: 0.85rem; }
.pl-skill-add { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 0.5rem; }
.pl-skill-suggest { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 0.5rem; }
.pl-skill-chip__remove { margin-left: 0.15rem; }

/* Profile settings — skills & commissions sections */
.pl-profile-section { margin-top: 1.5rem; padding-top: 1.25rem; border-top: 1px solid var(--hub-border); }
.pl-profile-section__title { font-size: 1rem; font-weight: 700; margin: 0 0 0.5rem; }
.pl-commission-note { display: block; margin-top: 0.5rem; }

/* Profile settings — "Edit your profile" heading + Member/Instructor sub-tabs */
.pl-profile-heading { font-size: 1.25rem; font-weight: 700; margin: 0 0 1rem; color: var(--hub-text); }
.pl-subtabs { display: flex; gap: 0.5rem; margin-bottom: 1.25rem; flex-wrap: wrap; }

/* ========================================
   Member Home / Dashboard
   ======================================== */

/* Shared section heading + card spacing for the home blocks. */
.pl-home-heading {
    font-size: 1.05rem;
    font-weight: 700;
    margin: 0 0 1rem;
}
.pl-home-block { margin-bottom: 1.5rem; }

/* Empty-state line inside a home block. */
.pl-home-empty {
    color: var(--hub-text-muted);
    font-size: 0.9375rem;
    margin: 0;
}
.pl-home-empty a { color: var(--hub-link); font-weight: 500; }
.pl-home-empty a:hover { color: var(--hub-link-hover); }

/* --- Finish-your-profile nudge --- */
.pl-nudge {
    position: relative;
    margin-bottom: 1.5rem;
    border-left: 3px solid var(--color-tuscan-yellow);
}
.pl-nudge__lead { margin: 0 0 0.75rem; max-width: 60ch; }
.pl-nudge__close {
    position: absolute;
    top: 1rem;
    right: 1rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: var(--hub-text-muted);
    cursor: pointer;
    transition: background-color 0.15s ease, color 0.15s ease;
}
.pl-nudge__close:hover { background: var(--hub-surface); color: var(--hub-text); }
.pl-nudge__progress {
    height: 6px;
    border-radius: 999px;
    background: var(--hub-surface);
    overflow: hidden;
    margin-bottom: 0.75rem;
    max-width: 320px;
}
.pl-nudge__bar { height: 100%; background: var(--color-tuscan-yellow); border-radius: 999px; }
.pl-nudge__list {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 0 0 1rem;
    padding: 0;
}
.pl-nudge__list li {
    font-size: 0.8125rem;
    padding: 0.2rem 0.6rem;
    border-radius: 999px;
    background: var(--hub-surface);
    color: var(--hub-text-muted);
}
.pl-nudge__actions { display: flex; flex-wrap: wrap; gap: 0.5rem; }

/* --- Get started onboarding checklist --- */
.pl-onboarding {
    position: relative;
    margin-bottom: 1.5rem;
    border-left: 3px solid var(--color-tuscan-yellow);
}
.pl-onboarding__title { margin-bottom: 0.35rem; padding-right: 2.25rem; }
.pl-onboarding__lead { margin: 0 0 1rem; max-width: 60ch; }
.pl-onboarding__close {
    position: absolute;
    top: 1rem;
    right: 1rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: var(--hub-text-muted);
    cursor: pointer;
    transition: background-color 0.15s ease, color 0.15s ease;
}
.pl-onboarding__close:hover { background: var(--hub-surface); color: var(--hub-text); }
.pl-onboarding__steps {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin-bottom: 1rem;
}
.pl-onboarding-step {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    /* Never wrap the icon/label/arrow row — long labels wrap inside
       __body (min-width: 0) instead of shattering the row on phones. */
    flex-wrap: nowrap;
    padding: 0.75rem 0.9rem;
    border: 1px solid var(--hub-card-border);
    border-radius: 10px;
    color: var(--hub-text);
    text-decoration: none;
    transition: border-color 0.15s ease, background-color 0.15s ease;
}
.pl-onboarding-step:hover { border-color: var(--color-tuscan-yellow); background: var(--hub-surface); }
.pl-onboarding-step__status {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    color: var(--hub-text-muted);
}
.pl-onboarding-step--done .pl-onboarding-step__status { color: var(--color-tuscan-yellow); }
.pl-onboarding-step__body {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 0;
}
.pl-onboarding-step__label {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    font-weight: 500;
}
.pl-onboarding-step__note { font-size: 0.8125rem; }
.pl-onboarding-step__tag {
    font-size: 0.6875rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-weight: 600;
    padding: 0.1rem 0.45rem;
    border-radius: 999px;
    background: var(--hub-surface);
    color: var(--hub-text-muted);
}
.pl-onboarding-step__go { flex: 0 0 auto; display: inline-flex; color: var(--hub-text-muted); }
.pl-onboarding__progress { margin: 0; font-size: 0.875rem; }

/* --- Quick links --- */
.pl-quicklinks {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 0.75rem;
    margin-bottom: 1.5rem;
}
.pl-quicklink {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.9rem 1rem;
    border: 1px solid var(--hub-card-border);
    border-radius: 10px;
    background: var(--hub-card-bg);
    color: var(--hub-text);
    text-decoration: none;
    transition: border-color 0.15s ease, transform 0.1s ease, background-color 0.15s ease;
}
.pl-quicklink:hover {
    border-color: var(--color-tuscan-yellow);
    background: var(--hub-surface);
    transform: translateY(-1px);
}
.pl-quicklink__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 34px;
    height: 34px;
    border-radius: 8px;
    background: rgba(238, 180, 75, 0.15);
    color: var(--color-tuscan-yellow);
}
.pl-quicklink__label { font-size: 0.9375rem; font-weight: 500; }

/* --- Your upcoming --- */
.pl-upcoming { list-style: none; margin: 0; padding: 0; }
.pl-upcoming__item + .pl-upcoming__item { border-top: 1px solid var(--hub-border); }
.pl-upcoming__link {
    display: flex;
    align-items: baseline;
    gap: 1rem;
    padding: 0.75rem 0;
    text-decoration: none;
    color: var(--hub-text);
}
.pl-upcoming__link:hover .pl-upcoming__title { color: var(--hub-link); }
.pl-upcoming__when {
    flex-shrink: 0;
    width: 6.5rem;
    display: flex;
    flex-direction: column;
    line-height: 1.3;
}
.pl-upcoming__date { font-size: 0.875rem; font-weight: 700; }
.pl-upcoming__time { font-size: 0.8125rem; color: var(--hub-text-muted); }
.pl-upcoming__body { display: flex; flex-direction: column; gap: 0.25rem; min-width: 0; }
.pl-upcoming__title { font-size: 0.9375rem; font-weight: 500; }
.pl-upcoming__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.8125rem;
}
.pl-upcoming__kind {
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    padding: 0.1rem 0.45rem;
    border-radius: 10px;
    background: var(--hub-blue-soft);
    color: var(--hub-blue);
}
/* Sibling of .pl-upcoming__link (never nested inside it — no <a> in <a>). Same pill
   formula as .pl-calendar-list__register so "Join online" reads consistently everywhere
   it appears. Indented to sit under the title/meta column (date column is 6.5rem + 1rem gap). */
.pl-upcoming__join {
    display: inline-block;
    margin: -0.4rem 0 0.75rem 7.5rem;
    font-size: 0.6875rem;
    font-weight: 700;
    padding: 2px 8px;
    border-radius: 4px;
    background: color-mix(in srgb, var(--color-tuscan-yellow) 15%, transparent);
    color: var(--color-tuscan-yellow);
    text-decoration: none;
    letter-spacing: 0.04em;
    transition: background 0.15s;
}
.pl-upcoming__join:hover {
    background: color-mix(in srgb, var(--color-tuscan-yellow) 28%, transparent);
}

/* --- Latest announcements --- */
.pl-ann-list { list-style: none; margin: 0; padding: 0; }
.pl-ann { padding: 0.85rem 0; }
.pl-ann + .pl-ann { border-top: 1px solid var(--hub-border); }
.pl-ann__title { font-size: 0.9375rem; font-weight: 600; margin-bottom: 0.2rem; }
.pl-ann__meta { font-size: 0.8125rem; margin-bottom: 0.4rem; }
.pl-ann__meta a { color: var(--hub-link); font-weight: 500; }
.pl-ann__meta a:hover { color: var(--hub-link-hover); }
.pl-ann__body { font-size: 0.875rem; color: var(--hub-text-muted); margin: 0; }

/* --- Your guilds (chips) --- */
.pl-guild-chips { display: flex; flex-wrap: wrap; gap: 0.6rem; }
.pl-guild-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.45rem 0.8rem;
    border: 1px solid var(--hub-card-border);
    border-radius: 999px;
    background: var(--hub-surface);
    color: var(--hub-text);
    text-decoration: none;
    font-size: 0.875rem;
    transition: border-color 0.15s ease, background-color 0.15s ease;
}
.pl-guild-chip:hover { border-color: var(--color-tuscan-yellow); background: var(--hub-card-bg); }
.pl-guild-chip__logo { flex-shrink: 0; }
.pl-guild-chip__name { font-weight: 500; }
.pl-guild-chip__badge {
    font-size: 0.625rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    padding: 0.1rem 0.4rem;
    border-radius: 8px;
    background: rgba(238, 180, 75, 0.15);
    color: var(--color-tuscan-yellow);
}

/* Home blocks stack their date column on narrow screens. */
@media (max-width: 520px) {
    .pl-upcoming__link { flex-direction: column; gap: 0.25rem; }
    .pl-upcoming__when { flex-direction: row; gap: 0.5rem; width: auto; }
    .pl-upcoming__join { margin-left: 0; }
}

/* Guild editor "Share & Print" QR preview. The QR SVG (segno, scale=1) is tiny
   at intrinsic size, so scale it up to a fixed preview box. */
.pl-qr-preview {
    flex: 0 0 auto;
    width: 140px;
    height: 140px;
    padding: 8px;
    background: #ffffff;
    border: 1px solid var(--hub-border);
    border-radius: 6px;
}

.pl-qr-preview svg {
    display: block;
    width: 100%;
    height: 100%;
}

/* "Share & Print" QR card — a vertical card shared by the class edit split (right half)
   and the community-event edit form (full width). Layout only; every color is a theme
   token, so it reads correctly on both Obsidian (dark) and Slate (light). */
.pl-qr-share__title {
    margin: 0 0 0.35rem;
}

.pl-qr-share__hint {
    font-size: 0.8125rem;
    margin: 0 0 1.25rem;
}

.pl-qr-share__qr {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 1.25rem;
}

.pl-qr-share .pl-qr-preview {
    width: 168px;
    height: 168px;
}

.pl-qr-share__qr-caption {
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--hub-text-muted);
}

.pl-qr-share__field {
    margin-bottom: 1rem;
}

.pl-qr-share__link {
    display: flex;
    gap: 0.5rem;
    align-items: center;
}

.pl-qr-share__link input {
    flex: 1 1 auto;
    min-width: 0;
}

.pl-qr-share__link .hub-btn {
    flex: 0 0 auto;
    min-width: 4.75rem;
}

.pl-qr-share__actions {
    display: flex;
    gap: 0.75rem;
    flex-wrap: wrap;
}

/* Before publication the download links are absent and this one line takes their place. */
.pl-qr-share__locked {
    font-size: 0.8125rem;
    margin: 0;
}

/* Printable-flyer button sits just below the Share & Print card in the edit-page aside. */
.pl-qr-share__flyer {
    margin-top: 0.75rem;
}

/* The Share & Print card on the live class edit page, between Locked Details and the form. */
.pl-live-edit-share {
    margin: 0 0 1.5rem;
}

/* Class-edit 6/6 split: identity fields (title, slug, category, instructor) on the left,
   the Share & Print card on the right. Stacks on narrow screens with the QR card on top. */
.pl-edit-split {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1.5rem;
    align-items: start;
    margin-bottom: 0.5rem;
}

.pl-edit-split__main {
    min-width: 0;
}

@media (max-width: 800px) {
    .pl-edit-split {
        grid-template-columns: 1fr;
    }
    .pl-edit-split__side {
        order: -1;
    }
}

/* ========================================
   Public event detail page (/events/<pk>/) — a centered single column of cards.
   Layout + theme tokens only, so it reads correctly on both Obsidian (dark) and
   Slate (light) and for the anonymous public-topbar view. Reused by templates/404.html.
   ======================================== */
.pl-event-detail {
    max-width: 640px;
    margin: 0 auto;
}

.pl-event-detail__card {
    padding: 1.75rem;
}

.pl-event-detail__kind {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
}

.pl-event-detail__guild {
    display: inline-block;
    padding: 0.2rem 0.6rem;
    border-radius: 999px;
    background: var(--hub-surface);
    color: var(--color-tuscan-yellow);
    font-size: 0.8125rem;
    font-weight: 600;
    text-decoration: none;
}

.pl-event-detail__guild:hover {
    background: var(--hub-elevated);
}

.pl-event-detail__type {
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--hub-text-muted);
}

.pl-event-detail__badge {
    display: inline-block;
    padding: 0.2rem 0.6rem;
    border-radius: 999px;
    border: 1px solid var(--hub-border);
    color: var(--hub-text-muted);
    font-size: 0.75rem;
    font-weight: 600;
}

.pl-event-detail__title {
    margin: 0 0 1rem;
}

.pl-event-detail__row {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin: 0 0 0.6rem;
    color: var(--hub-text);
}

.pl-event-detail__icon {
    flex: 0 0 auto;
    color: var(--hub-text-muted);
}

.pl-event-detail__past {
    margin: 0.75rem 0 0;
    color: var(--hub-text-muted);
    font-style: italic;
}

.pl-event-detail__description {
    margin-top: 1.25rem;
    color: var(--hub-text);
    line-height: 1.6;
}

.pl-event-detail__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-top: 1.75rem;
}

/* Who's coming — read-only attendee roster + the RSVP toggle. Layout only; every color
   comes from theme tokens, so it reads on both Obsidian (dark) and Slate (light). */
.pl-event-detail__attendees {
    margin-top: 1.75rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--hub-border);
}

.pl-event-detail__attendees-heading {
    margin: 0 0 0.75rem;
    font-size: 1rem;
    color: var(--hub-text);
}

.pl-event-detail__attendee-list {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 0 0 1rem;
    padding: 0;
    list-style: none;
}

.pl-event-detail__attendee {
    padding: 0.2rem 0.6rem;
    border-radius: 999px;
    background: var(--hub-surface);
    color: var(--hub-text);
    font-size: 0.8125rem;
}

.pl-event-detail__attendees-empty {
    margin: 0 0 1rem;
    color: var(--hub-text-muted);
}

.pl-event-detail__rsvp-form {
    margin: 0;
}

/* ========================================
   My Guilds settings tab — per-guild join/leave toggle list.
   Layout only; every color comes from theme tokens (hub-card wrapper, --hub-text,
   --hub-text-muted, --hub-border) and the switch is the already-themed pl-toggle,
   so this reads correctly on both Obsidian (dark) and Slate (light) with no rules
   of its own. Reflows to a single column; no table, no fixed widths, no h-scroll.
   ======================================== */
.pl-guild-toggle-list {
    display: flex;
    flex-direction: column;
}

.pl-guild-toggle-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.75rem 0;
    border-top: 1px solid var(--hub-border);
    transition: opacity 0.15s ease;
}

.pl-guild-toggle-row:first-child {
    border-top: 0;
}

/* In-flight: the whole row dims and locks while its join/leave POST is on the wire.
   htmx tags only the firing element with .htmx-request, so the toggle carries
   hx-indicator="closest .pl-guild-toggle-row" to lift the class up to the row. */
.pl-guild-toggle-row.htmx-request {
    opacity: 0.5;
    pointer-events: none;
}

.pl-guild-toggle-row__info {
    /* min-width:0 lets the hint truncate instead of stretching the flex row. */
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}

.pl-guild-toggle-row__name {
    color: var(--hub-text);
    font-weight: 500;
}

.pl-guild-toggle-row__hint {
    font-size: 0.8rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ── First-login guild updates prompt (/welcome/guild-updates/) ────────────
   Layout only (max-width, spacing) — the card, rows, toggles, and buttons are
   all existing themed components, so no colors belong here. */
.pl-guild-prompt {
    max-width: 640px;
    margin: 0 auto;
}

.pl-guild-prompt__title {
    font-size: 1.4rem;
}

.pl-guild-prompt__intro {
    margin-bottom: 1.25rem;
}

.pl-guild-prompt__error {
    margin-bottom: 0.75rem;
}

/* Button row clears the last guild row (Rule 18); Save sits last/rightmost. */
.pl-guild-prompt__actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.75rem;
    margin-top: 1.5rem;
}

@media (max-width: 480px) {
    .pl-guild-prompt__actions {
        flex-direction: column-reverse;
    }

    .pl-guild-prompt__actions .pl-btn {
        width: 100%;
    }
}

/* ── Guild-announcement Discord channel picker ─────────────────────────────
   A single-choice radio group (one-of-N destination). Theme tokens only — no
   inline background/color, no --surface. Verified on dark (Obsidian) + light
   (Slate). See templates/hub/partials/_announcement_channel_picker.html. */
.pl-channel-picker {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin-top: 0.25rem;
}

.pl-channel-option {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    padding: 0.625rem 0.75rem;
    background: var(--hub-surface);
    border: 1px solid var(--hub-border);
    border-radius: 8px;
    cursor: pointer;
    font-size: 0.9375rem;
    color: var(--hub-text);
}

.pl-channel-option input[type="radio"] {
    flex: 0 0 auto;
    width: auto;
    margin: 0;
    padding: 0;
    background: none;
    border: none;
    accent-color: var(--color-tuscan-yellow);
    cursor: pointer;
}

.pl-channel-option__label {
    flex: 1 1 auto;
}

.pl-channel-option__hint {
    flex: 0 0 auto;
    font-size: 0.8125rem;
    color: var(--hub-text-muted);
}

/* :checked lives on the input; style the enclosing label via :has (option card). */
.pl-channel-option:has(input:checked) {
    border-color: var(--color-tuscan-yellow);
    background: var(--hub-elevated);
}

.pl-channel-option--disabled,
.pl-channel-option:has(input:disabled) {
    opacity: 0.55;
    cursor: not-allowed;
}

.pl-channel-option--disabled input[type="radio"] {
    cursor: not-allowed;
}

.pl-channel-picker__empty {
    margin: 0.5rem 0 0;
    font-size: 0.8125rem;
    color: var(--hub-text-muted);
}

/* Generic stacked radio option cards (profile marketing opt-in). */
.pl-radio-group {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.pl-radio-option {
    display: flex;
    align-items: flex-start;
    gap: 0.625rem;
    padding: 0.625rem 0.75rem;
    background: var(--hub-surface);
    border: 1px solid var(--hub-border);
    border-radius: 8px;
    cursor: pointer;
    font-size: 0.9375rem;
    color: var(--hub-text);
}

.pl-radio-option input[type="radio"] {
    flex: 0 0 auto;
    width: auto;
    margin: 0.2rem 0 0;
    padding: 0;
    background: none;
    border: none;
    accent-color: var(--color-tuscan-yellow);
    cursor: pointer;
}

.pl-radio-option__label {
    flex: 1 1 auto;
}

/* :checked lives on the input; style the enclosing label via :has (option card). */
.pl-radio-option:has(input:checked) {
    border-color: var(--color-tuscan-yellow);
    background: var(--hub-elevated);
}

/* ============================================================================
   Release-update email composer + preview  (Site Settings → Announcements)
   Admin-page chrome only — the iframe content is the email itself.
   ========================================================================== */
.pl-announce-tab {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
    max-width: 760px;
}

.pl-release-form__error {
    background: var(--color-error-bg);
    border: 1px solid var(--color-error);
    border-radius: 6px;
    padding: 0.6rem 0.85rem;
    color: var(--color-error);
    font-size: 0.875rem;
}
.pl-release-form__warn {
    margin: 0;
    color: var(--hub-text-muted);
    font-size: 0.875rem;
    font-style: italic;
}
.pl-release-cards {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}
.pl-release-cards__title {
    margin: 0;
    font-size: 0.95rem;
    color: var(--hub-text);
}
.pl-release-cards__hint {
    margin: -0.25rem 0 0.25rem;
    font-size: 0.8125rem;
    color: var(--hub-text-muted);
}
.pl-release-card {
    display: grid;
    grid-template-columns: 1fr 280px;
    gap: 1rem;
    align-items: start;
    padding: 0.9rem 1rem;
    border: 1px solid var(--hub-border);
    border-radius: 8px;
    background: var(--hub-surface);
}
.pl-release-card__name {
    display: block;
    color: var(--hub-text);
    font-size: 0.9375rem;
}
.pl-release-card__bullets {
    margin: 0.4rem 0 0;
    padding-left: 1.1rem;
    color: var(--hub-text-muted);
    font-size: 0.8125rem;
    line-height: 1.5;
}
.pl-release-card__bullets li { margin-bottom: 0.2rem; }
.pl-release-card__note {
    margin: 0.5rem 0 0;
    font-size: 0.8125rem;
    color: var(--hub-link);
}
.pl-release-card__controls {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}
.pl-release-actions {
    display: flex;
    gap: 0.75rem;
    align-items: center;
    flex-wrap: wrap;
    margin-top: 0.25rem;
}

/* --- The upgraded preview (device frame, inbox row, HTML/plain-text toggle) --- */
.pl-email-preview__title {
    margin: 0 0 0.25rem;
    font-size: 0.95rem;
    color: var(--hub-text);
}
.pl-email-preview__lead {
    margin: 0 0 0.9rem;
    color: var(--hub-text-muted);
    font-size: 0.875rem;
}
.pl-email-preview__inbox {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    padding: 0.7rem 0.9rem;
    border: 1px solid var(--hub-border);
    border-radius: 8px 8px 0 0;
    background: var(--hub-elevated);
}
.pl-email-preview__from { font-size: 0.75rem; color: var(--hub-text-muted); font-weight: 700; }
.pl-email-preview__subject { font-size: 0.9375rem; color: var(--hub-text); font-weight: 700; }
.pl-email-preview__preheader { font-size: 0.8125rem; color: var(--hub-text-muted); }
.pl-email-preview__toolbar {
    display: flex;
    gap: 0.75rem;
    flex-wrap: wrap;
    padding: 0.6rem 0.9rem;
    border: 1px solid var(--hub-border);
    border-top: none;
    background: var(--hub-surface);
}
.pl-seg {
    display: inline-flex;
    border: 1px solid var(--hub-border-strong);
    border-radius: 6px;
    overflow: hidden;
}
.pl-seg__btn {
    border: none;
    background: transparent;
    color: var(--hub-text-muted);
    font-family: var(--font-body);
    font-size: 0.8125rem;
    font-weight: 600;
    padding: 0.35rem 0.85rem;
    cursor: pointer;
}
.pl-seg__btn + .pl-seg__btn { border-left: 1px solid var(--hub-border-strong); }
.pl-seg__btn--active {
    background: var(--color-tuscan-yellow);
    color: var(--color-navy);
}
.pl-email-preview__pane { display: block; }
.pl-email-preview__frame {
    display: flex;
    justify-content: center;
    overflow-x: auto;
    padding: 1rem;
    border: 1px solid var(--hub-border);
    border-top: none;
    border-radius: 0 0 8px 8px;
    background: var(--hub-surface);
}
.pl-email-preview__iframe {
    height: 620px;
    max-width: 100%;
    border: 1px solid var(--hub-border-strong);
    border-radius: 8px;
    background: #fff;
}
.pl-email-preview__text {
    margin: 0;
    padding: 1rem;
    border: 1px solid var(--hub-border);
    border-top: none;
    border-radius: 0 0 8px 8px;
    background: var(--hub-input-bg);
    color: var(--hub-text);
    font-size: 0.8125rem;
    line-height: 1.5;
    white-space: pre-wrap;
    word-break: break-word;
    max-height: 620px;
    overflow-y: auto;
}

@media (max-width: 640px) {
    .pl-release-card { grid-template-columns: 1fr; }
}

/* ── Announcement compose wizard (/announcements/compose/) ───────────────────
   One Alpine-stepper page. Every step gets its display from a class (never inline
   on an x-show element — Rule 12); every color is a theme token. */
.pl-wizard-lead {
    color: var(--hub-text-muted);
    margin: -0.5rem 0 1.25rem;
    max-width: 60ch;
}
.pl-wizard { display: flex; flex-direction: column; gap: 1.5rem; }
.pl-wizard-nav {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 0;
    padding: 0;
    list-style: none;
}
.pl-wizard-nav__step {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.4rem 0.85rem;
    border-radius: 999px;
    border: 1px solid var(--hub-border);
    background: var(--hub-surface);
    color: var(--hub-text-muted);
    font-size: 0.8125rem;
    font-weight: 500;
}
.pl-wizard-nav__n {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.35rem;
    height: 1.35rem;
    border-radius: 50%;
    background: var(--hub-elevated);
    color: var(--hub-text-muted);
    font-size: 0.75rem;
    font-weight: 700;
}
.pl-wizard-nav__step.is-active {
    border-color: var(--color-tuscan-yellow);
    color: var(--hub-text);
}
.pl-wizard-nav__step.is-active .pl-wizard-nav__n {
    background: var(--color-tuscan-yellow);
    color: var(--color-navy);
}
.pl-wizard-nav__step.is-done .pl-wizard-nav__n {
    background: var(--hub-blue);
    color: #fff;
}
.pl-wizard-step { display: block; }
.pl-wizard-field { display: block; }
.pl-wizard-errors { margin-bottom: 1rem; }
.pl-wizard-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    align-items: center;
    margin-top: 1.5rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--hub-border);
}
.pl-wizard-preview {
    display: block;
    margin-top: 1rem;
}
.pl-wizard-preview__bar {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-bottom: 0.75rem;
}
.pl-wizard-preview__pane { min-height: 200px; }
.pl-wizard-preview__loading {
    color: var(--hub-text-muted);
    font-size: 0.875rem;
    padding: 2rem 1rem;
    text-align: center;
}
.pl-wizard-preview__frame {
    max-height: 520px;
    overflow: auto;
}
.pl-wizard-preview__iframe {
    width: 100%;
    height: 520px;
    max-width: 100%;
    border: 1px solid var(--hub-border-strong);
    border-radius: 0 0 8px 8px;
    background: #fff;
}
.pl-wizard-reach {
    margin: 1.25rem 0 0;
    color: var(--hub-text);
    font-size: 0.9375rem;
}
.pl-mention-picker { display: block; margin-top: 1.25rem; }
.pl-field-hint--warn {
    color: var(--color-tuscan-yellow);
    font-weight: 600;
    margin-top: 0.35rem;
}
/* Flat composer: locked-audience banner, delivery-option sections, phone-tray push preview */
.pl-compose-section {
    margin-top: 1.5rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--hub-border);
}
.pl-compose-section__title {
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--color-tuscan-yellow);
    text-transform: capitalize;
    margin: 0 0 0.85rem;
}
.pl-compose-section__note {
    color: var(--hub-text-muted);
    font-size: 0.875rem;
    margin: 0 0 1rem;
}
.pl-compose-hint {
    padding-top: 1rem;
    margin: 0;
}
.pl-compose-channel {
    margin-top: 1rem;
    padding: 1rem 1.1rem 1.15rem;
    border: 1px solid var(--hub-border);
    border-radius: 12px;
    background: var(--hub-surface);
}
.pl-compose-channel__title {
    font-size: 1.25rem;
    font-weight: 700;
    margin: 0 0 0.75rem;
    color: var(--color-tuscan-yellow);
    text-transform: capitalize;
}
.pl-compose-channel__actions {
    margin-top: 0.85rem;
}
.pl-phase-tabs {
    display: flex;
    gap: 0.5rem;
    margin-bottom: 1.25rem;
    border-bottom: 1px solid var(--hub-border);
}
.pl-phase-tab {
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    padding: 0.5rem 0.9rem;
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--hub-text-muted);
    cursor: pointer;
    font-family: var(--font-body);
}
.pl-phase-tab--active {
    color: var(--hub-text);
    border-bottom-color: var(--color-tuscan-yellow);
}
/* Composer additions to the phase tabs: a completion mark, a done state, an error state.
   The announcement composer never sets these, so it is unchanged. */
.pl-phase-tab__mark {
    margin-left: 0.35rem;
    font-size: 0.8em;
}
.pl-phase-tab--done {
    color: var(--hub-text);
}
.pl-phase-tab--done .pl-phase-tab__mark {
    color: var(--pl-lifecycle-live);
}
.pl-phase-tab--error {
    color: var(--pl-lifecycle-cancelled);
    border-bottom-color: var(--pl-lifecycle-cancelled);
}
.pl-phase-tab--error .pl-phase-tab__mark {
    color: var(--pl-lifecycle-cancelled);
}
@media (max-width: 640px) {
    /* One scrolling row on phones; the composer's goTo() scrolls the active tab into view. */
    .pl-phase-tabs {
        flex-wrap: nowrap;
        overflow-x: auto;
        scrollbar-width: none;
        scroll-snap-type: x proximity;
    }
    .pl-phase-tabs::-webkit-scrollbar { display: none; }
    .pl-phase-tab {
        flex: 0 0 auto;
        scroll-snap-align: start;
    }
}

/* ── Class composer (teach + admin class form) ──────────────────────────────
   Five Alpine steps in one form (classes/_components/class_composer.html). Every step
   gets its display from a class, never inline on an x-show element (Rule 12); every
   colour is a theme token. Mirrors .pl-wizard. */
.pl-composer { display: flex; flex-direction: column; gap: 1.5rem; }
.pl-composer__title { margin: 0 0 0.5rem; }
.pl-composer__step { display: block; }
.pl-composer__heading {
    margin: 0 0 0.5rem;
    font-size: 1.35rem;
}
.pl-composer__pipeline { margin: 1rem 0; }
.pl-composer__card { margin: 0 0 1rem; }
.pl-composer__card-title { margin: 0; }
.pl-composer__footnote {
    margin: 0.75rem 0 0;
    color: var(--hub-text-muted);
}
/* "Step 3 of 5", phones only: the tab bar alone does not say where you are when half of it is off screen. */
.pl-composer-count {
    display: none;
    margin: 0 0 0.5rem;
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--hub-text-muted);
}
@media (max-width: 640px) {
    .pl-composer-count { display: block; }
}
/* Server rendered summary of every broken step, above the tabs; each row jumps to its step. */
.pl-composer-errors {
    border: 1px solid var(--pl-lifecycle-cancelled);
    border-radius: 8px;
    padding: 0.85rem 1rem;
    margin-bottom: 1.25rem;
}
.pl-composer-errors__title {
    font-weight: 700;
    margin: 0 0 0.5rem;
}
.pl-composer-errors__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}
.pl-composer-errors__jump {
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    color: var(--pl-lifecycle-cancelled);
    text-align: left;
    text-decoration: underline;
    font-family: var(--font-body);
    font-size: inherit;
}
/* The Still Missing notice: a refused submit or publish is a checklist, not a form error, so it
   wears the review note gold instead of the error red. Above the steps, so it shows on the step
   the composer lands on (the first one owing an item). */
.pl-composer-missing {
    border: 1px solid var(--color-tuscan-yellow);
    border-radius: 8px;
    padding: 0.85rem 1rem;
    background: rgba(238, 180, 75, 0.08);
}
.pl-composer-missing__title {
    font-weight: 700;
    margin: 0 0 0.25rem;
}
.pl-composer-missing__lead {
    margin: 0;
    color: var(--hub-text-muted);
}
/* What the browser is holding for you (issue #368, item 3c): the offer to restore a draft this
   device kept, or the line saying it is being kept, plus the way to drop it. Rendered hidden and
   only shown by static/js/composer_draft.js, which is why the [hidden] overrides are here: the
   container sets display:flex and .hub-btn sets display:inline-block, and both would otherwise
   beat the browser's own [hidden] rule. */
.pl-composer-draft {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 1.25rem;
    padding: 0.6rem 0.9rem;
    border: 1px solid var(--hub-border);
    border-radius: 8px;
    background: var(--hub-surface);
    font-size: 0.9rem;
    color: var(--hub-text-muted);
}
.pl-composer-draft[hidden] { display: none; }
.pl-composer-draft__line {
    flex: 1 1 18rem;
    margin: 0;
}
.pl-composer-draft__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}
.pl-composer-draft .hub-btn[hidden] { display: none; }

/* The one action bar, outside every step, sticky. Opaque so page content never shows through. */
.pl-composer-bar {
    position: sticky;
    bottom: 0;
    z-index: 5;
    display: flex;
    gap: 0.75rem;
    flex-wrap: wrap;
    align-items: center;
    margin-top: 1.5rem;
    padding: 1rem 0;
    border-top: 1px solid var(--hub-border);
    background: var(--hub-card-bg);
}
.pl-composer-bar__spacer { flex: 1; }
@media (max-width: 480px) {
    .pl-composer-bar__primary { flex: 1 1 100%; }
    .pl-composer-bar__primary .hub-btn { width: 100%; }
}
/* Step 5 readiness hints jump to their step instead of a hash link to a hidden field. */
.pl-readiness__jump {
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    color: inherit;
    font: inherit;
    text-align: left;
    text-decoration: underline;
}
/* The quick Submit on Manage My Classes and the class page while a draft is unready: the reason is
   written beside the disabled button, never only in a hover bubble a disabled control cannot open. */
.pl-submit-gate {
    display: inline-flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.25rem;
    max-width: 18rem;
}
.pl-submit-gate--end {
    align-items: flex-end;
    text-align: right;
}
/* The sale modal body (classes/_components/sale_form.html). */
.pl-sale-form__intro { margin: 0 0 1rem; }
.pl-sale-form__field { display: block; }
.pl-sale-form__price {
    margin: 0.5rem 0 1.25rem;
    font-weight: 600;
    color: var(--hub-text);
}
.pl-sale-note {
    font-size: 0.8rem;
    color: var(--hub-text-muted);
}
.pl-recipient-add {
    margin-top: 1.25rem;
    margin-bottom: 0;
}
.pl-recipient-add select {
    max-width: 28rem;
}
.pl-compose-locked {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.7rem 0.95rem;
    margin-bottom: 1.5rem;
    border-radius: 10px;
    border: 1px solid var(--hub-border);
    background: var(--hub-surface);
    color: var(--hub-text);
    font-weight: 600;
}
.pl-compose-locked__label {
    color: var(--hub-text-muted);
    font-weight: 400;
}
.pl-push-preview { margin-top: 0.6rem; }
.pl-push-preview__label {
    color: var(--hub-text-muted);
    font-size: 0.8125rem;
    margin-bottom: 0.4rem;
}
.pl-push-preview__card {
    display: flex;
    gap: 0.7rem;
    align-items: flex-start;
    padding: 0.7rem 0.9rem;
    border-radius: 0.6rem;
    background: #0f172a;
    color: #e2e8f0;
    max-width: 26rem;
}
.pl-push-preview__icon {
    flex: 0 0 auto;
    width: 2rem;
    height: 2rem;
    border-radius: 0.4rem;
    background: #1e293b;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1rem;
}
.pl-push-preview__meta { min-width: 0; }
.pl-push-preview__app {
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: #94a3b8;
}
.pl-push-preview__title {
    font-weight: 600;
    font-size: 0.9rem;
    margin-top: 0.1rem;
    overflow-wrap: anywhere;
}
.pl-push-preview__body {
    font-size: 0.85rem;
    margin-top: 0.1rem;
    overflow-wrap: anywhere;
    opacity: 0.6;
}
/* Push-test device inventory rows (admin diagnostics) */
.pl-device-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
.pl-device-row {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.55rem 0.75rem;
    border-radius: 0.5rem;
    background: rgba(128, 128, 128, 0.12);
}
.pl-device-row__meta { font-size: 0.8rem; }
/* Admin Tools hub: a grid of tool cards */
.pl-tools-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(16.5rem, 1fr));
    gap: 1rem;
    margin-top: 1.5rem;
}
.pl-tool-card {
    display: flex;
    flex-direction: column;
    gap: 0.65rem;
    text-decoration: none;
    color: inherit;
    transition: border-color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
}
.pl-tool-card:hover {
    border-color: var(--color-tuscan-yellow);
    transform: translateY(-2px);
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
}
.pl-tool-card__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.5rem;
    height: 2.5rem;
    border-radius: 0.6rem;
    background: rgba(238, 180, 75, 0.12);
    color: var(--color-tuscan-yellow);
}
.pl-tool-card__title {
    font-weight: 700;
    font-size: 1.05rem;
    color: var(--hub-text);
}
.pl-tool-card__desc {
    color: var(--hub-text-muted);
    font-size: 0.875rem;
    line-height: 1.45;
}
.pl-spin {
    display: none;
    width: 13px;
    height: 13px;
    vertical-align: -2px;
    margin-right: 4px;
    border: 2px solid rgba(255, 255, 255, 0.35);
    border-top-color: currentColor;
    border-radius: 50%;
    animation: pl-spin 0.7s linear infinite;
}
.htmx-request .pl-spin, .pl-spin.htmx-request { display: inline-block; }
@keyframes pl-spin { to { transform: rotate(360deg); } }

/* "Your drafts" list (below the wizard) */
.pl-drafts { margin-top: 1.5rem; }
.pl-drafts__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1rem;
}
.pl-drafts__title { margin: 0; font-size: 1.05rem; }
.pl-drafts__empty { color: var(--hub-text-muted); margin: 0; }
.pl-draft-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    padding: 0.85rem 0;
    border-top: 1px solid var(--hub-border);
}
.pl-draft-row__meta { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.pl-draft-row__title { color: var(--hub-text); }
.pl-draft-row__sub { color: var(--hub-text-muted); font-size: 0.8125rem; }
.pl-draft-row__actions { display: flex; gap: 0.5rem; flex-shrink: 0; }
.pl-draft-row__delete { margin-left: 0.25rem; }

@media (max-width: 480px) {
    .pl-draft-row { align-items: flex-start; }
    .pl-draft-row__actions { width: 100%; }
    .pl-wizard-actions .hub-btn { flex: 1 1 auto; }
}

/* ── Site Settings tab panels ────────────────────────────────────────────────
   The stacked layout of one x-show tab panel. This MUST be a class and never an
   inline style="display:flex". Alpine's x-show reveals an element with
   el.style.removeProperty('display'), which deletes an inline display:flex and
   drops the panel back to display:block — silently taking `gap` with it, because
   gap does nothing on a block box. Every section on the panel then sits flush
   against the next one, which is exactly how the CMS tab shipped. Declared here,
   the inline display:none that x-show writes still wins while hidden, and removing
   it falls back to this flex box instead of to nothing.
   ======================================================================== */
.pl-settings-tab {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}

/* The General tab's fields are single rows rather than sections, so they sit closer. */
.pl-settings-tab--tight { gap: 1.25rem; }

/* ── Slideshow admin page (/manage/slideshow/) ───────────────────────────────
   Editor UI for the signage slideshow. Renders under hub/base.html (hub.css +
   components.css), NOT signage.css. Layout lives in classes, never inline on an
   x-show element (Rule 12). Controls are themed by .pl-form-group (components.css). */
/* The Slideshow admin page root. Also the Alpine x-data host — see slideshow.html.
   .hub-card carries no margin of its own, so this gap is what keeps the three cards
   from butting flush (Rule 18). */
.pl-slideshow-page {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}


.pl-slideshow-rows {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.pl-slideshow-row {
    padding: 1rem;
    background: rgba(255, 255, 255, 0.02);
}

/* Kind-switching field groups — display is in the class so Alpine's x-show only
   toggles display:none (Rule 12), never stripping an inline display. */
.pl-slide-fields {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.pl-slideshow-daterow {
    display: flex;
    gap: 1rem;
    flex-wrap: wrap;
}

.pl-slideshow-daterow > * {
    flex: 1;
    min-width: 160px;
}

.pl-slideshow-empty {
    color: var(--hub-text-muted);
    font-style: italic;
    padding: 0.75rem 0;
}

/* Compact slide card: a collapsed summary row that expands to the full editor. The
   summary reads at a glance — thumbnail, title, kind, screen, on/off. */
.pl-slide-card {
    padding: 0;
    overflow: hidden;
}

.pl-slide-summary {
    display: flex;
    align-items: center;
    gap: 0.875rem;
    width: 100%;
    padding: 0.75rem 0.875rem;
    color: var(--hub-text);
    flex-wrap: wrap;
}

/* Drag-to-reorder grip. Hidden on touch (native DnD is unreliable there) — the up/down
   buttons drive reordering on a phone/tablet. */
.pl-slide-grip {
    flex: 0 0 auto;
    cursor: grab;
    color: var(--hub-text-muted);
    font-size: 1.05rem;
    line-height: 1;
    padding: 0.25rem 0.15rem;
    user-select: none;
    touch-action: none;
}

.pl-slide-grip:active {
    cursor: grabbing;
}

.pl-slide-card--dragging {
    opacity: 0.4;
}

.pl-slide-card--drag-over {
    box-shadow: inset 0 3px 0 0 var(--color-tuscan-yellow);
}

.pl-slide-summary__actions {
    flex: 0 0 auto;
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.pl-slide-move {
    display: inline-flex;
    gap: 0.25rem;
}

.pl-slide-move__btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border-radius: 6px;
    border: 1px solid var(--hub-border);
    background: var(--hub-surface);
    color: var(--hub-text);
    cursor: pointer;
    font-size: 0.85rem;
    line-height: 1;
    transition: background 0.15s ease;
}

.pl-slide-move__btn:hover {
    background: var(--hub-elevated);
}

@media (hover: none) {
    .pl-slide-grip {
        display: none;
    }
}

.pl-slide-summary__thumb {
    flex: 0 0 auto;
    width: 64px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    border-radius: 6px;
    border: 1px solid var(--hub-border);
    background: var(--hub-surface);
}

.pl-slide-summary__thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.pl-slide-summary__thumb--placeholder {
    color: var(--hub-text-muted);
}

.pl-slide-summary__main {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}

.pl-slide-summary__title {
    font-weight: 600;
    font-size: 0.9375rem;
    color: var(--hub-text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.pl-slide-summary__meta {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    font-size: 0.75rem;
    color: var(--hub-text-muted);
}

.pl-slide-badge {
    display: inline-flex;
    align-items: center;
    padding: 0.05rem 0.45rem;
    border-radius: 999px;
    border: 1px solid var(--hub-border);
    background: var(--hub-surface);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--hub-text-muted);
}

.pl-slide-summary__state {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
}

.pl-slide-summary__state::before {
    content: "";
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: currentColor;
}

.pl-slide-summary__state--on {
    color: #4ade80;
}

.pl-slide-summary__state--off {
    color: var(--hub-text-muted);
}

/* Editor panel the Edit button reveals. Display lives in the class, never inline on
   the x-show element (Rule 12). */
.pl-slide-editor {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    padding: 0.5rem 0.875rem 0.875rem;
    border-top: 1px solid var(--hub-border);
}

.pl-slide-image__label {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}

.pl-slide-image-preview {
    margin: 0.25rem 0;
}

.pl-slide-image-preview img {
    max-width: 240px;
    max-height: 135px;
    border-radius: 8px;
    border: 1px solid var(--hub-border);
    display: block;
}

/* Per-saved-zone setup helpers: the copyable URL, QR, copy + preview buttons. */
.pl-slideshow-zone__setup {
    margin-top: 1rem;
    padding: 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    border: 1px solid var(--hub-border);
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.02);
}

.pl-slideshow-zone__url {
    font-family: ui-monospace, "SFMono-Regular", Menlo, monospace;
    font-size: 0.9375rem;
    color: var(--hub-text);
    word-break: break-all;
    user-select: all;
}

.pl-slideshow-zone__actions {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.pl-slideshow-zone__qr {
    width: 128px;
    height: 128px;
    padding: 0.5rem;
    background: #ffffff;
    border-radius: 8px;
}

.pl-slideshow-zone__qr svg {
    display: block;
    width: 100%;
    height: 100%;
}

@media (max-width: 640px) {
    .pl-slideshow-daterow { flex-direction: column; }
}

/* Guild announcement reach — collapsible recipient list (guild edit → Announcements tab) */
.pl-recipient-list {
  margin-top: 0.75rem;
  max-height: 14rem;
  overflow-y: auto;
  overflow-x: auto;
  padding: 0.75rem 1rem;
  border: 1px solid var(--hub-input-border);
  border-radius: 6px;
  background: var(--hub-surface);
  color: var(--hub-text);
}
.pl-recipient-list ul { margin: 0; padding-left: 1.1rem; }
.pl-recipient-list li { overflow-wrap: anywhere; word-break: break-all; line-height: 1.5; }

/* Per-announcement email recipient checklist (compose wizard → Step 2). Collapsible card with a
   real, styled checkbox per member + custom address. Themed via tokens (both light + dark). */
.pl-recipient-card {
  margin: 0.85rem 0 0.25rem;
  padding: 0.9rem 1rem;
  background: var(--hub-surface);
  border: 1px solid var(--hub-border);
  border-radius: 10px;
}
.pl-recipient-card__head {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}
.pl-recipient-card__title { margin: 0; }
.pl-recipient-card__summary {
  margin: 0.35rem 0 0.6rem;
  font-size: 0.9375rem;
  color: var(--hub-text-muted);
}
.pl-recipient-card__toggle { margin: 0; }
.pl-recipient-card__body { margin-top: 0.75rem; }

.pl-recipient-checklist__note {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  color: var(--hub-text-muted);
  font-size: 0.875rem;
  margin: 0.75rem 0 0.85rem;
}
.pl-recipient-checklist__tools {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 0.6rem;
}
.pl-recipient-checklist {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  max-height: 18rem;
  overflow-y: auto;
  padding: 0.15rem;
}
.pl-recipient-checklist__row {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.5rem 0.7rem;
  background: var(--hub-card-bg);
  border: 1px solid var(--hub-border);
  border-radius: 8px;
  cursor: pointer;
  font-size: 0.9375rem;
  color: var(--hub-text);
}
/* Reset the global full-width input rule + colour the tick with the tuscan accent (light + dark). */
.pl-recipient-checklist__row input[type="checkbox"] {
  flex: 0 0 auto;
  width: auto;
  margin: 0;
  padding: 0;
  accent-color: var(--color-tuscan-yellow);
  cursor: pointer;
}
.pl-recipient-checklist__label {
  flex: 1 1 auto;
  overflow-wrap: anywhere;
  word-break: break-word;
}
/* :checked lives on the input; light up the enclosing row via :has (like .pl-channel-option). */
.pl-recipient-checklist__row:has(input:checked) {
  border-color: var(--color-tuscan-yellow);
  background: var(--hub-elevated);
}
.pl-recipient-checklist__empty {
  margin: 0.25rem 0 0;
  font-size: 0.875rem;
  color: var(--hub-text-muted);
}

/* ── Interactive space map ──────────────────────────────────────────────────
   The map is DRAWN, not photographed: .pl-map-canvas is a blank slab of the
   floor's aspect ratio and every room is a .pl-map-marker--region shape on it,
   so the plan is crisp at any zoom and follows the theme. An uploaded floor
   image, when there is one, sits behind at low opacity as a tracing guide only.

   Rooms reuse existing status colours only: --color-success (available), the
   caution hue #fbbf24 already used by .hub-pill--warn (maintenance) and
   --hub-text-muted (occupied). No new colour VALUES are introduced here —
   deliberately not --color-tuscan-yellow, which is the primary CTA gold and
   would make a maintenance space read like a primary button. The alpha-varied
   rgba() fills below are those same three hues, not new ones. */
.pl-map { margin: 0; }
/* The listings table is wider than a phone. .hub-content is a flex item, and a flex item
   defaults to min-width:auto — it refuses to shrink below its content's min-content width,
   so the table's width was pushing the whole page sideways instead of scrolling inside
   .pl-map-list__scroll. min-width:0 lets it shrink and hands the overflow back to the
   scroll container.

   Scoped with :has() to pages that actually carry the map rather than applied to the shared
   chrome, so nothing else in the app changes. Browsers without :has() simply keep today's
   behaviour. */
.hub-main-wrapper:has(.pl-map),
.hub-main-wrapper:has(.pl-map) .hub-content {
  min-width: 0;
}

/* Map / Listings tabs on the Spaces page. Same .vote-tab buttons the guild pages use;
   this only supplies the rule they sit on. x-cloak'd in the markup, so a reader with no
   JavaScript never sees a tab strip that cannot switch. */
.pl-space-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0;
  border-bottom: 1px solid var(--hub-border);
  margin-bottom: 1rem;
}

.pl-map-switch {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  margin-bottom: 0.75rem;
}
.pl-map-switch__btn {
  padding: 0.4rem 0.9rem;
  border: 1px solid var(--hub-border);
  border-radius: 6px;
  background: var(--hub-surface);
  color: var(--hub-text-muted);
  font-size: 0.875rem;
  cursor: pointer;
}
.pl-map-switch__btn.is-active {
  border-color: var(--color-tuscan-yellow);
  color: var(--hub-text);
  background: var(--hub-elevated);
}
.pl-map-toolbar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-bottom: 0.5rem;
}
.pl-map-toolbar__hint { font-size: 0.75rem; }
.pl-map-viewport {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--hub-border);
  border-radius: 8px;
  background: var(--hub-surface);
  touch-action: none;
  cursor: grab;
  /* Cap the frame so a tall floor (the 2nd floor is nearly square) is cropped
     rather than filling the page — the crop is what gives drag and two-finger
     swipe somewhere to go before any zoom. Centring the stage keeps the crop
     symmetric, matching the JS clamp's centre-origin maths. */
  max-height: min(85vh, 900px);
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.pl-map-viewport:active { cursor: grabbing; }
.pl-map-stage {
  position: relative;
  width: 100%;
  flex: none;
  transform-origin: center center;
  transition: transform 0.12s ease-out;
}
@media (prefers-reduced-motion: reduce) {
  .pl-map-stage { transition: none; }
}
/* The drawn floor slab. Its height comes from the per-floor aspect-ratio inline
   style, so it needs no image to give it size. */
.pl-map-canvas {
  position: relative;
  width: 100%;
  background: var(--hub-surface);
  background-image:
    linear-gradient(to right, var(--hub-border) 1px, transparent 1px),
    linear-gradient(to bottom, var(--hub-border) 1px, transparent 1px);
  background-size: 5% 5%;
}
/* An uploaded plan is a tracing guide, never the map itself. */
.pl-map-underlay {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: fill;
  opacity: 0.18;
  user-select: none;
  -webkit-user-drag: none;
}
/* Mobile: give the map viewport a fixed window so a wide floor's short (unscaled)
   aspect-ratio height doesn't collapse the frame to a sliver once space_map.js opens
   it at MOBILE_BASE_SCALE. Keep this breakpoint in sync with space_map.js. */
@media (max-width: 768px) {
  .pl-map-viewport {
    height: min(70vh, 560px);
  }
}
/* Caption clarifying the S1-x markers are cubby shelves. */
.pl-map-cubby-note {
  margin: 0.25rem 0 0.5rem;
  font-size: 0.8125rem;
}
/* Legend — the colour key, with live counts */
.pl-map-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1rem;
  margin: 0 0 0.5rem;
  padding: 0;
  list-style: none;
  font-size: 0.75rem;
  color: var(--hub-text-muted);
}
.pl-map-legend__item { display: flex; align-items: center; gap: 0.35rem; }
.pl-map-legend__swatch {
  width: 0.75rem;
  height: 0.75rem;
  border-radius: 3px;
  border: 1px solid var(--hub-text-muted);
  background: rgba(139, 151, 168, 0.2);
}
.pl-map-legend__swatch--available {
  border-color: var(--color-success);
  background: rgba(123, 200, 143, 0.35);
}
.pl-map-legend__swatch--occupied {
  border-color: var(--hub-text-muted);
  background: rgba(139, 151, 168, 0.2);
}
.pl-map-legend__swatch--maintenance {
  border-color: #fbbf24;
  background: rgba(251, 191, 36, 0.3);
}
.pl-map-legend__count { font-weight: 700; color: var(--hub-text); }
.pl-map-caption {
  margin: 0.6rem 0 0;
  color: var(--hub-text-muted);
  font-size: 0.85rem;
}
.pl-map-admin { margin: 1rem 0 0; }

/* Drawn rooms + pins */
.pl-map-marker {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.2rem;
  padding: 0;
  border-radius: 3px;
  border: 1px solid var(--hub-text-muted);
  background: rgba(139, 151, 168, 0.22);
  color: var(--hub-text);
  font-size: 0.7rem;
  font-weight: 600;
  line-height: 1.15;
  text-align: center;
  cursor: pointer;
  overflow: hidden;
  transition: background-color 0.12s ease-out, box-shadow 0.12s ease-out;
}
@media (prefers-reduced-motion: reduce) {
  .pl-map-marker { transition: none; }
}
.pl-map-marker:hover,
.pl-map-marker:focus-visible {
  background: rgba(139, 151, 168, 0.4);
  box-shadow: 0 0 0 1px var(--hub-text-muted);
  z-index: 3;
}
.pl-map-marker:focus-visible {
  outline: 2px solid var(--hub-blue);
  outline-offset: 1px;
}
.pl-map-marker--pin {
  width: auto;
  height: auto;
  min-width: 1.5rem;
  padding: 0.15rem 0.4rem;
  border-radius: 999px;
  transform: translate(-50%, -50%);
  z-index: 2;
}
/* Available is the call to action: the strongest fill and the only lit border. */
.pl-map-marker--available {
  border-color: var(--color-success);
  background: rgba(123, 200, 143, 0.3);
  box-shadow: inset 0 0 0 1px var(--color-success);
}
.pl-map-marker--available:hover,
.pl-map-marker--available:focus-visible {
  background: rgba(123, 200, 143, 0.55);
  box-shadow: 0 0 0 2px var(--color-success);
}
.pl-map-marker--occupied {
  border-color: var(--hub-text-muted);
  background: rgba(139, 151, 168, 0.22);
  color: var(--hub-text-muted);
}
.pl-map-marker--occupied:hover,
.pl-map-marker--occupied:focus-visible {
  background: rgba(139, 151, 168, 0.4);
  color: var(--hub-text);
}
.pl-map-marker--maintenance {
  border-color: #fbbf24;
  background: rgba(251, 191, 36, 0.25);
}
.pl-map-marker--maintenance:hover,
.pl-map-marker--maintenance:focus-visible {
  background: rgba(251, 191, 36, 0.45);
  box-shadow: 0 0 0 1px #fbbf24;
}
/* Shops, restrooms, stairs — present but deliberately quiet. */
.pl-map-marker--info {
  border-style: dashed;
  background: rgba(139, 151, 168, 0.12);
  color: var(--hub-text-muted);
  font-weight: 500;
}
.pl-map-marker--pending { border-style: dashed; border-width: 2px; }
/* Walls — a solid structural bar, not a control: no dashed border, no text, no hover. */
.pl-map-marker--wall {
  border: none;
  border-radius: 2px;
  background: var(--hub-text);
  opacity: 0.72;
  color: transparent;
  cursor: default;
  box-shadow: none;
}
.pl-map-marker--wall:hover,
.pl-map-marker--wall:focus-visible {
  background: var(--hub-text);
  box-shadow: none;
}
/* In the editor a wall is still draggable and clickable, so it keeps a grab affordance. */
.pl-map-editor .pl-map-marker--wall {
  cursor: grab;
  opacity: 0.8;
}
.pl-map-marker__body {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.05rem;
  max-width: 100%;
  padding: 0 0.15rem;
  overflow: hidden;
}
.pl-map-marker__code {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}
.pl-map-marker__meta {
  font-weight: 400;
  font-size: 0.85em;
  opacity: 0.85;
  white-space: nowrap;
}
.pl-map-marker--region { font-size: 0.65rem; }
/* How much text a shape can hold is decided by MapHotspot.detail_level. A code-only room
   gets the smaller type so a four-character code still fits between its walls. */
.pl-map-marker--text-label.pl-map-marker--region { font-size: 0.55rem; }
.pl-map-marker--text-label .pl-map-marker__body { padding: 0 1px; }
.pl-map-marker--text-label .pl-map-marker__meta,
.pl-map-marker--text-minimal .pl-map-marker__body { display: none; }
.pl-map-marker__dot {
  position: absolute;
  top: 1px;
  right: 2px;
  font-size: 0.9rem;
  line-height: 1;
}

/* Accessible list — the keyboard equal of the map */
.pl-map-list { margin-top: 1.5rem; }
.pl-map-list__h3 { margin: 0 0 0.25rem; font-size: 1rem; }
.pl-map-list__intro { margin: 0 0 1rem; font-size: 0.8125rem; }
.pl-map-list__floor { margin: 1rem 0 0.5rem; font-size: 0.875rem; }
.pl-map-list__empty { margin: 0 0 0.5rem; font-size: 0.875rem; }
.pl-map-list__scroll { overflow-x: auto; }
.pl-map-list__table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.875rem;
}
.pl-map-list__table th,
.pl-map-list__table td {
  padding: 0.5rem 0.6rem;
  text-align: left;
  border-bottom: 1px solid var(--hub-border);
  vertical-align: middle;
}
.pl-map-list__table thead th {
  color: var(--hub-text-muted);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.pl-map-list__code { white-space: nowrap; }
.pl-map-list__note { font-size: 0.8125rem; }
.pl-map-list__withdraw { margin-left: 0.5rem; }
/* Filter bar — search box + status chips, above the table for the selected floor. */
.pl-map-list__controls {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.75rem 1rem;
  margin: 0 0 0.75rem;
}
.pl-map-list__search { display: flex; flex: 1 1 16rem; flex-direction: column; gap: 0.25rem; max-width: 22rem; }
.pl-map-list__label {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--hub-text-muted);
}
.pl-map-list__search-input {
  width: 100%;
  padding: 0.4rem 0.6rem;
  border-radius: 6px;
  border: 1px solid var(--hub-input-border);
  background: var(--hub-input-bg);
  color: var(--hub-text);
  font-size: 0.875rem;
}
.pl-map-list__search-input:focus-visible {
  outline: 2px solid var(--hub-blue);
  outline-offset: 1px;
}
.pl-map-list__chips { display: flex; flex-wrap: wrap; gap: 0.35rem; }
.pl-map-list__chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.3rem 0.65rem;
  border-radius: 999px;
  border: 1px solid var(--hub-border);
  background: var(--hub-surface);
  color: var(--hub-text-muted);
  font-size: 0.75rem;
  font-weight: 600;
  cursor: pointer;
}
.pl-map-list__chip:hover { color: var(--hub-text); border-color: var(--hub-text-muted); }
.pl-map-list__chip:focus-visible {
  outline: 2px solid var(--hub-blue);
  outline-offset: 1px;
}
.pl-map-list__chip.is-active {
  border-color: var(--color-tuscan-yellow);
  background: var(--hub-elevated);
  color: var(--hub-text);
}
.pl-map-list__chip-count { color: var(--hub-text-muted); font-weight: 400; }
.pl-map-list__chip.is-active .pl-map-list__chip-count { color: var(--color-tuscan-yellow); }
/* A filtered-out row leaves the page and the accessibility tree together. */
.pl-map-list__row[hidden] { display: none; }
.pl-map-list__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1rem;
  margin-top: 0.75rem;
}
.pl-map-list__count { margin: 0; font-size: 0.8125rem; color: var(--hub-text-muted); }
/* Show more / Show fewer and Clear filters are answers the browser gives, so they stay
   hidden until Alpine turns them on — with JavaScript off the whole list is already there
   and neither control would have anything to do. */
.pl-map-list .pl-map-list__more,
.pl-map-list .pl-map-list__clear { display: none; }
.pl-map-list .pl-map-list__more.is-shown,
.pl-map-list .pl-map-list__clear.is-shown { display: inline-flex; }
[data-theme="light"] .pl-map-list .hub-pill--ok { color: #1f7a52; }
[data-theme="light"] .pl-map-list .hub-pill--warn { color: #9a6a00; }
[data-theme="light"] .pl-map-list .hub-pill--neutral { color: #5b6675; }
[data-theme="light"] .pl-map-detail .hub-pill--ok { color: #1f7a52; }
[data-theme="light"] .pl-map-detail .hub-pill--warn { color: #9a6a00; }
[data-theme="light"] .pl-map-detail .hub-pill--neutral { color: #5b6675; }

/* Detail panel (inside components/modal.html) */
.pl-map-detail__head {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin-bottom: 0.75rem;
}
.pl-map-detail__title { margin: 0; font-size: 1.125rem; }
.pl-map-detail__edit { margin-left: auto; }
.pl-map-detail__edit svg { margin-right: 0.3rem; }
.pl-map-detail__photo {
  display: block;
  width: 100%;
  max-height: 220px;
  object-fit: cover;
  border-radius: 8px;
  border: 1px solid var(--hub-border);
  margin-bottom: 0.75rem;
}
.pl-map-detail__facts {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.35rem 1rem;
  margin: 0 0 0.75rem;
  font-size: 0.875rem;
}
.pl-map-detail__facts dt { color: var(--hub-text-muted); }
.pl-map-detail__facts dd { margin: 0; }
.pl-map-detail__blurb { margin: 0 0 1rem; font-size: 0.875rem; }

/* Occupant cards — opted-in members only, shown to logged-in members only */
.pl-map-occupants { margin: 0 0 1rem; }
.pl-map-occupants__heading {
  margin: 0 0 0.5rem;
  font-size: 0.8125rem;
  font-weight: 700;
  color: var(--hub-text-muted);
  text-transform: capitalize;
}
.pl-map-occupant {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--hub-border);
  border-radius: 8px;
  background: var(--hub-surface);
}
.pl-map-occupant + .pl-map-occupant { margin-top: 0.5rem; }
.pl-map-occupant__avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  flex: 0 0 40px;
  border-radius: 50%;
  background: var(--hub-elevated);
  color: var(--hub-text-muted);
  font-weight: 700;
  font-size: 0.875rem;
}
.pl-map-occupant__avatar--photo { object-fit: cover; }
.pl-map-occupant__body { min-width: 0; }
.pl-map-occupant__name { font-weight: 600; font-size: 0.9375rem; }
.pl-map-occupant__pronouns {
  margin-left: 0.4rem;
  font-size: 0.75rem;
  font-weight: 400;
  color: var(--hub-text-muted);
}
.pl-map-occupant__skills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  margin-top: 0.3rem;
}
.pl-map-detail__cta { margin-top: 1rem; }
.pl-map-detail__note { margin: 0.5rem 0; font-size: 0.8125rem; }
.pl-map-request-form { margin-top: 0.75rem; }
.pl-map-request-form__actions {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-top: 0.75rem;
}

/* Your space requests card on /info/ */
.pl-map-mine__row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--hub-border);
}
.pl-map-mine__row:last-child { border-bottom: 0; }
.pl-map-mine__code { font-weight: 600; }
[data-theme="light"] .pl-map-mine .hub-pill--warn { color: #9a6a00; }

/* Reviewer queue */
.pl-map-review__back { margin-bottom: 0.75rem; }
.pl-map-review__lede { margin: -0.25rem 0 1.5rem; max-width: 65ch; }
.pl-map-review { padding: 1.5rem; }
.pl-map-review__list { display: flex; flex-direction: column; gap: 1.25rem; }
.pl-map-review__row {
  padding: 1rem;
  background: var(--hub-surface);
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}
.pl-map-review__body { flex: 1; min-width: 220px; }
.pl-map-review__title { font-weight: 600; }
.pl-map-review__meta { font-size: 0.8125rem; margin-top: 0.25rem; }
.pl-map-review__message { margin: 0.5rem 0 0; font-size: 0.875rem; }
.pl-map-review__controls { display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center; }
.pl-map-review__gap { width: 0.5rem; }
.pl-map-review__empty { margin: 0; }
.pl-map-review__intro { margin: 0 0 1rem; font-size: 0.875rem; }
.pl-map-review__actions { margin-top: 1rem; }
.pl-map-review__grow { flex: 1; }

/* Admin placement editor */
.pl-map-edit__header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}
.pl-map-edit__done { white-space: nowrap; }
.pl-map-edit__actions-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}
.pl-map-edit__lede { margin-bottom: 1.5rem; max-width: 65ch; }
.pl-map-edit__tabs {
  display: flex;
  border-bottom: 1px solid var(--hub-border);
  gap: 0;
  margin-bottom: 1.5rem;
  flex-wrap: wrap;
}
.pl-map-edit__card { padding: 1.5rem; margin-bottom: 1.5rem; }
.pl-map-edit__h2 { margin: 0 0 0.25rem; }
.pl-map-edit__hint { font-size: 0.8125rem; margin: 0 0 1rem; }
.pl-map-edit__empty { margin: 0; }
.pl-map-edit__rows { display: flex; flex-direction: column; gap: 1rem; }
.pl-map-edit__row { padding: 1rem; background: var(--hub-surface); }
.pl-map-edit__hidden { display: none; }
.pl-map-edit__delete { margin-top: 0.75rem; }
.pl-map-edit__add { margin-top: 1rem; }
.pl-map-edit__save { margin-top: 1rem; }
.pl-map-edit__select {
  width: 100%;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--hub-input-border);
  border-radius: 6px;
  background: var(--hub-input-bg);
  color: var(--hub-text);
}
.pl-map-edit__select option {
  background: var(--hub-input-bg);
  color: var(--hub-text);
}
.pl-map-warn {
  color: #fbbf24;
  background-color: rgba(251, 191, 36, 0.12);
  border-left-color: #fbbf24;
}
[data-theme="light"] .pl-map-warn { color: #9a6a00; }
.pl-map-editor__stage {
  position: relative;
  border: 1px solid var(--hub-border);
  border-radius: 8px;
  overflow: hidden;
  touch-action: none;
}
.pl-map-editor__status--error { color: #f0a0a0; }
[data-theme="light"] .pl-map-editor__status--error { color: #b03030; }

/* Click-a-tile marker editor (the "Edit marker" modal). */
.pl-marker-edit {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.pl-marker-edit__status {
  margin: 0;
  padding: 0.75rem;
  border: 1px solid var(--hub-border);
  border-radius: 8px;
  background: var(--hub-elevated);
}
.pl-marker-edit__status legend {
  padding: 0 0.35rem;
  font-weight: 600;
  color: var(--hub-text);
}
.pl-marker-edit__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.5rem;
}
.pl-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.35rem 0.7rem;
  border: 1px solid var(--hub-border);
  border-radius: 999px;
  background: var(--hub-elevated);
  font-size: 0.9rem;
  cursor: pointer;
}
.pl-chip input {
  margin: 0;
}
.pl-chip:has(input:checked) {
  border-color: var(--hub-blue);
  background: var(--hub-blue-soft);
  color: var(--hub-text);
  font-weight: 600;
}
.pl-marker-edit__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  justify-content: space-between;
}

/* ══════════════════════════════════════════════════════════════════════════
   Guided tours (Spec C) — the offer card, entry links, the Help-page card,
   and the Driver.js popover restyle. Every color is a theme token, so both
   themes (Obsidian dark + Slate light) come free.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── The offer card (§6.1) — fixed bottom-right, non-blocking ── */
.pl-tour-offer {
    position: fixed;
    right: 1.5rem;
    bottom: 1.5rem;
    z-index: 400; /* just below modals (backdrop 500) */
    max-width: 20rem;
    padding: 1rem;
    background: var(--hub-elevated);
    border: 1px solid var(--hub-border);
    border-radius: 12px;
    box-shadow: 0 8px 30px rgba(0, 0, 0, 0.35);
}

.pl-tour-offer__lead {
    margin: 0 0 0.75rem;
    color: var(--hub-text);
    font-size: 0.9rem;
    line-height: 1.45;
}

.pl-tour-offer__actions {
    display: flex;
    gap: 0.5rem;
}

@media (max-width: 768px) {
    /* Stretches to a bottom bar that clears the 52px feedback FAB — both stay
       fully visible and tappable (chosen over hiding the FAB). */
    .pl-tour-offer {
        left: 1rem;
        right: 1rem;
        max-width: none;
        bottom: calc(env(safe-area-inset-bottom, 0px) + 1rem + 52px + 0.75rem);
    }

    .pl-tour-offer__actions .pl-btn {
        flex: 1;
        min-height: 44px;
    }
}

/* ── Guided-tour "advancing" affordance: a brief scrim + spinner during a hop,
      so a boosted swap or tab flip never flashes the destination bare. ── */
.pl-tour-advancing {
    position: fixed;
    inset: 0;
    z-index: 10001;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    background: color-mix(in srgb, var(--hub-bg) 72%, transparent);
    backdrop-filter: blur(2px);
    color: var(--hub-text);
    font-size: 0.9rem;
}
.pl-tour-advancing[hidden] { display: none; }

.pl-tour-advancing__spinner {
    width: 28px;
    height: 28px;
    border: 3px solid var(--hub-border);
    border-top-color: var(--color-tuscan-yellow);
    border-radius: 50%;
    animation: pl-spin 0.7s linear infinite;
}

.pl-tour-advancing__label {
    color: var(--hub-text);
}

@media (prefers-reduced-motion: reduce) {
    .pl-tour-advancing__spinner {
        animation: none;
        border-color: var(--color-tuscan-yellow);
    }
}

/* ── Paused-tour pill (§6.2) — a persistent Resume affordance that survives
   navigation while a tour is paused, so the presenter can roam and come back ── */
.pl-tour-resume {
    position: fixed;
    right: 1rem;
    bottom: 1rem;
    z-index: 10000;
    display: flex;
    align-items: center;
    gap: 0.625rem;
    padding: 0.5rem 0.5rem 0.5rem 0.875rem;
    background: var(--hub-card-bg);
    color: var(--hub-text);
    border: 1px solid var(--hub-border);
    border-left: 3px solid var(--color-tuscan-yellow);
    border-radius: 999px;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.28);
    max-width: calc(100vw - 2rem);
}
.pl-tour-resume[hidden] { display: none; }

.pl-tour-resume__label {
    font-size: 0.8125rem;
    font-weight: 600;
    white-space: nowrap;
}

.pl-tour-resume__end {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.5rem;
    height: 1.5rem;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: transparent;
    color: var(--hub-text-muted);
    font-size: 1rem;
    line-height: 1;
    cursor: pointer;
}
.pl-tour-resume__end:hover,
.pl-tour-resume__end:focus {
    background: var(--hub-border);
    color: var(--hub-text);
}

@media (max-width: 480px) {
    .pl-tour-resume {
        left: 1rem;
        right: 1rem;
        justify-content: space-between;
    }
}

/* Driver's footer packs its three children (pause, "N of M", nav buttons) with no
   gap, so the pause control ends up jammed against the step counter. Give the row a
   gap so nothing touches. */
.pl-tour .driver-popover-footer {
    gap: 0.5rem;
}

/* The Pause control inside the Driver.js popover footer (a subtle ghost pill sitting
   left of the "N of M" counter and Back/Next). Styled as a real button so it reads as
   a control and never visually merges with the counter text. */
.pl-tour .pl-tour-pause-btn {
    padding: 0.25rem 0.6rem;
    background: transparent;
    border: 1px solid var(--hub-border);
    border-radius: 8px;
    color: var(--hub-text-muted);
    font: inherit;
    font-size: 0.8125rem;
    font-weight: 500;
    line-height: 1.3;
    text-decoration: none;
    text-shadow: none; /* driver's default footer-button white text-shadow must be reset */
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease;
}
.pl-tour .pl-tour-pause-btn:hover,
.pl-tour .pl-tour-pause-btn:focus {
    background: transparent; /* override driver's default #f7f7f7 hover fill */
    color: var(--color-tuscan-yellow);
    border-color: var(--color-tuscan-yellow);
}

/* ── "Show me around" entry link under a page header (§6.3) ── */
.pl-tour-entry-link {
    margin: -0.75rem 0 1.25rem;
}

/* ── Help-page "Guided tours" card rows (§6.5) ── */
.pl-tour-rows {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.pl-tour-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.pl-tour-card__heading {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}
.pl-tour-card__heading .hub-detail-label {
    margin-bottom: 0;
}

.pl-tour-card__explainer {
    margin: 0.25rem 0 0.75rem;
    font-size: 0.8125rem;
}

.pl-tour-row__title {
    color: var(--hub-text);
    font-size: 0.9rem;
}

/* Taken / not-taken state: a checked green circle vs an empty one. The green is
   the theme-aware sync token, softened with color-mix for the fill so it reads
   on both Obsidian and Slate cards. */
.pl-tour-row__status {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 1.125rem;
    height: 1.125rem;
    border-radius: 50%;
    border: 2px solid var(--hub-border-strong);
}
.pl-tour-row__status--done {
    border-color: transparent;
    background: color-mix(in srgb, var(--pl-sync-synced) 22%, transparent);
    color: var(--pl-sync-synced);
}
.pl-tour-row__status--done svg {
    width: 0.75rem;
    height: 0.75rem;
}

.pl-tour-row__btn {
    margin-left: auto;
}

/* ── Driver.js popover restyle (§6.2) — scoped .driver-popover.pl-tour ── */
.driver-popover.pl-tour {
    background: var(--hub-elevated);
    color: var(--hub-text);
    border: 1px solid var(--hub-border);
    border-radius: 12px;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
    max-width: 20rem;
    font-family: 'Inter', sans-serif;
}

.pl-tour .driver-popover-title {
    font-family: 'Lato', sans-serif;
    font-weight: 700;
    color: var(--hub-text);
}

.pl-tour .driver-popover-description {
    color: var(--hub-text-muted);
    font-size: 0.9rem;
}

.pl-tour .driver-popover-progress-text {
    color: var(--hub-text-muted);
    font-size: 0.8rem;
}

.pl-tour .driver-popover-next-btn {
    background: var(--color-tuscan-yellow);
    color: var(--color-navy);
    text-shadow: none; /* driver's default text-shadow must be reset */
    border: 1px solid transparent;
    border-radius: 8px;
    font-weight: 600;
    padding: 0.35rem 0.85rem;
}

.pl-tour .driver-popover-next-btn:hover,
.pl-tour .driver-popover-next-btn:focus {
    background: #f5ca6e;
    color: var(--color-navy);
}

.pl-tour .driver-popover-prev-btn {
    background: transparent;
    border: 1px solid var(--hub-border);
    color: var(--hub-text);
    text-shadow: none;
    border-radius: 8px;
    padding: 0.35rem 0.85rem;
}

.pl-tour .driver-popover-prev-btn:hover,
.pl-tour .driver-popover-prev-btn:focus {
    background: var(--hub-surface);
    color: var(--hub-text);
}

.pl-tour .driver-popover-close-btn {
    color: var(--hub-text-muted);
}

.pl-tour .driver-popover-close-btn:hover,
.pl-tour .driver-popover-close-btn:focus {
    color: var(--hub-text);
}

/* Driver arrows are CSS-border triangles — repaint the visible side per side. */
.pl-tour .driver-popover-arrow-side-left {
    border-left-color: var(--hub-elevated);
}

.pl-tour .driver-popover-arrow-side-right {
    border-right-color: var(--hub-elevated);
}

.pl-tour .driver-popover-arrow-side-top {
    border-top-color: var(--hub-elevated);
}

.pl-tour .driver-popover-arrow-side-bottom {
    border-bottom-color: var(--hub-elevated);
}

@media (max-width: 768px) {
    .driver-popover.pl-tour {
        max-width: calc(100vw - 2rem);
    }

    .pl-tour .driver-popover-next-btn,
    .pl-tour .driver-popover-prev-btn {
        min-height: 44px;
    }
}

/* ── Instructor orientation (Spec D) ──────────────────────────────────── */

.pl-orientation {
    max-width: 860px;
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}

/* Friendly explainer — doubles as the redirect landing state. No error styling. */
.pl-orientation-banner {
    border-left: 4px solid var(--hub-accent, #c46a1b);
}

.pl-orientation-banner__title {
    margin: 0 0 0.5rem;
    font-size: 1.1rem;
}

.pl-orientation-banner__body {
    margin: 0;
    color: var(--hub-text-muted);
}

.pl-orientation-done__title {
    margin: 0 0 0.5rem;
    font-size: 1.1rem;
}

.pl-orientation-done__meta {
    margin: 0 0 1rem;
    color: var(--hub-text-muted);
}

.pl-orientation-done__actions {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.pl-orientation-guide-link {
    margin: 1.5rem 0 0;
}

/* The submit clears the toggle above it (FRONTEND.md rule 18). */
.pl-orientation-submit {
    margin-top: 1.5rem;
}

.pl-orientation-submit:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

@media (max-width: 480px) {
    .pl-orientation-submit,
    .pl-orientation-done__actions .pl-btn {
        width: 100%;
        text-align: center;
    }
}

/* ── Host a Workshop (.pl-teach-*) ──────────────────────────────────────
   The page inviting members to host a workshop. One centered column of
   hub-cards: a state banner, a gradient hero, a feature grid, a live catalog
   card, the steps, the asks, the questions, the guide, and the interest card.
   The steps, asks and questions are admin-edited rich text (or older Markdown)
   rendered into .pl-md; the modifiers below give each its shape. The money split
   is one figure (a bar over three tiles) and the questions and the guide sit on
   the shared .pl-disclosure. Theme tokens only, both themes. ── */

.pl-teach {
    max-width: 980px;
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}

/* The column gap owns the vertical rhythm here, so kill the children's own margins. */
.pl-teach > .hub-card,
.pl-teach > .pl-guild-hero {
    margin: 0;
}

.pl-teach-meta {
    margin: 0.75rem 0 0;
    color: var(--hub-text-muted);
    font-size: 0.875rem;
}

.pl-teach-section__title {
    margin: 0 0 0.5rem;
    font-size: 1.25rem;
}

/* Hero: a variant over .pl-guild-hero, exactly as .pl-help-hero composes over it.
   --noimg paints the brand gradient; there is deliberately no photo (a stock shot
   here would be a lie about the space, and the real photo belongs to the example
   class card below). Centered, and shorter than a guild hero. */
.pl-teach-hero {
    align-items: center;
    justify-content: center;
    text-align: center;
    min-height: clamp(200px, 26vw, 300px);
}

/* Cap the copy so the centered lead does not run the full 980px column. Same
   recipe as .pl-help-hero's content block. */
.pl-teach-hero .pl-guild-hero__content {
    width: 100%;
    max-width: 680px;
    padding: 2rem 1.5rem;
}

.pl-teach-hero__actions {
    display: flex;
    gap: 0.75rem;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    margin-top: 1rem;
}

/* Feature grid. Declarations are copied from .pl-tools-grid / .pl-tool-card so the
   two grids stay visually identical, but the names are new on purpose: those say
   "admin tools", they are built for links, and their hover lift is wrong on a card
   that does not go anywhere. */
.pl-feature-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(16.5rem, 1fr));
    gap: 1rem;
    margin-top: 1.5rem;
}

.pl-feature-card {
    display: flex;
    flex-direction: column;
    gap: 0.65rem;
    margin: 0;
}

.pl-feature-card__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.5rem;
    height: 2.5rem;
    border-radius: 0.6rem;
    background: rgba(238, 180, 75, 0.12);
    color: var(--color-tuscan-yellow);
}

.pl-feature-card__title {
    font-weight: 700;
    font-size: 1.05rem;
    color: var(--hub-text);
}

.pl-feature-card__desc {
    color: var(--hub-text-muted);
    font-size: 0.875rem;
    line-height: 1.45;
}

/* "See It For Yourself": copy left, a real catalog card right. Stacks at the same
   800px breakpoint .pl-edit-split uses, copy first (source order, no `order`). */
.pl-teach-showcase {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1.5rem;
    align-items: center;
    margin-top: 1rem;
}

.pl-teach-showcase__body {
    color: var(--hub-text-muted);
    margin: 0 0 0.75rem;
}

.pl-teach-showcase__caption {
    color: var(--hub-text-muted);
    font-size: 0.8125rem;
    margin-top: 0.5rem;
}

/* Pin the embedded grid to one column so the card does not stretch to the pane.
   Written as a two-class descendant because cms-public.css is linked in the
   template and therefore loads AFTER hub.css: a bare class would lose the cascade
   to `.cp-page .cls-grid`, and a template <style> block is not allowed (Rule 9). */
/* ── "Your Photo, Two Shapes" (composer step 2) ────────────────────────────
   Left pane: the 16:9 banner cropper. Right pane: the catalog card focal point tool,
   rendering the REAL .cls-media strip inside two card shaped frames. */
.pl-crop-pair {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1.25rem;
    align-items: start;
}
.pl-crop-pane { min-width: 0; }
.pl-crop-pane__label {
    margin: 0 0 0.5rem;
    font-size: 0.6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--hub-text-muted);
}
.pl-crop-pane__hint {
    font-size: 0.8125rem;
    color: var(--hub-text-muted);
    margin: 0.35rem 0 0.75rem;
}
@media (max-width: 800px) {
    .pl-crop-pair { grid-template-columns: 1fr; }
}
.pl-card-focus {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}
.pl-card-focus__frames {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}
.pl-card-focus__frame {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    max-width: 100%;
}
/* Frame widths, derived from the live catalog (cms-public.css), not guessed:
   .cp-page .cp-container is max-width 1100px with padding 0 24px and NO border-box
   reset anywhere in cms-public.css or hub.css, so the grid is the full 1100px on a
   wide screen. .cls-grid is repeat(auto-fill, minmax(min(260px, 100%), 1fr)) with a
   16px gap: four columns of (1100 - 3 * 16) / 4 = 263px. On a 390px phone the same
   padding leaves 390 - 48 = 342px, which packs one column of 342px. Redo this sum if
   --max, the container padding, or the grid gap ever move. */
.pl-card-focus__frame--laptop { width: 263px; }
.pl-card-focus__frame--phone { width: 342px; }
.pl-card-focus__frame-label {
    font-size: 0.6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--hub-text-muted);
}
.pl-card-focus__sliders {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin-top: 0.25rem;
}
.pl-card-focus__slider-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    min-height: 2.75rem;
}
.pl-card-focus__slider-label {
    font-size: 0.75rem;
    color: var(--hub-text-muted);
    min-width: 6.5rem;
}
.pl-card-focus__range {
    flex: 1;
    min-width: 0;
    accent-color: var(--color-tuscan-yellow);
}
.pl-card-focus__reset {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.75rem;
}
.pl-card-focus__note {
    font-size: 0.8125rem;
    color: var(--hub-text-muted);
    margin: 0.5rem 0 0;
}
/* The create mode skeleton card: the mirrored photo, the live title, and this one
   muted line where the dates, price and spots will be after the first save. */
.cp-page .pl-card-focus__skeleton-line {
    font-size: 12px;
    color: var(--hub-text-muted);
}
/* Empty state for the card preview: exactly the space the 150px card will occupy. */
.pl-preview-empty {
    border: 1px dashed var(--hub-border-strong);
    border-radius: 8px;
    height: 150px;
    display: grid;
    place-items: center;
    padding: 0 1rem;
    text-align: center;
    color: var(--hub-text-muted);
    font-size: 0.875rem;
}

.cp-page .cls-grid.pl-teach-showcase__grid {
    grid-template-columns: minmax(0, 320px);
}

@media (max-width: 800px) {
    .pl-teach-showcase {
        grid-template-columns: 1fr;
    }
}

/* "How It Works": the admin's plain Markdown `1. 2. 3.` list, numbered here with
   CSS counters so every step keeps the gold circle the hand built list used to
   carry. Deliberately NOT .pl-pipeline markup — that strip means "where your class
   is in review", which this is not. Two-class selectors so these beat the generic
   .pl-md list rules regardless of source order. */
.pl-md.pl-teach-steps-md ol {
    list-style: none;
    counter-reset: pl-teach-step;
    margin: 1rem 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

/* Block flow, not flex: Markdown gives us <li><strong>title</strong> description</li>, and a
   flex li would make the title and the bare description text sibling columns (the title then
   wraps mid phrase). The numeral is absolutely positioned in the left gutter instead. */
.pl-md.pl-teach-steps-md ol > li {
    counter-increment: pl-teach-step;
    position: relative;
    display: block;
    margin: 0;
    padding-left: 2.2rem;
    color: var(--hub-text-muted);
    font-size: 0.875rem;
    line-height: 1.5;
}

/* The gold numeral circle, copied from .pl-wizard-nav__n's active state. */
.pl-md.pl-teach-steps-md ol > li::before {
    content: counter(pl-teach-step);
    position: absolute;
    left: 0;
    top: 0.1rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 1.35rem;
    height: 1.35rem;
    border-radius: 50%;
    background: var(--color-tuscan-yellow);
    color: var(--color-navy);
    font-size: 0.75rem;
    font-weight: 700;
}

/* The bold lead of each step reads as its title, in the full text color. */
.pl-md.pl-teach-steps-md ol > li strong {
    display: block;
    margin-bottom: 0.15rem;
    color: var(--hub-text);
    font-size: 1rem;
}

/* "What We Ask Of You": the editor's plain <ul> becomes a grid of cards, each with the
   gold check circle that is the steps' numeral treatment. Paragraphs outside a list
   render as ordinary .pl-md prose. Two-class selectors beat the generic .pl-md rules. */
.pl-md.pl-teach-asks-md {
    color: var(--hub-text-muted);
}

.pl-md.pl-teach-asks-md ul {
    list-style: none;
    margin: 0.75rem 0 0;
    padding: 0;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.75rem;
}

.pl-md.pl-teach-asks-md ul > li {
    position: relative;
    margin: 0;
    padding: 0.85rem 1rem 0.85rem 2.6rem;
    background: var(--hub-surface);
    border: 1px solid var(--hub-border);
    border-radius: 10px;
    color: var(--hub-text);
    font-size: 0.9375rem;
    line-height: 1.45;
}

.pl-md.pl-teach-asks-md ul > li::before {
    content: "\2713";
    position: absolute;
    left: 0.85rem;
    top: 0.85rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.35rem;
    height: 1.35rem;
    border-radius: 50%;
    background: var(--color-tuscan-yellow);
    color: var(--color-navy);
    font-size: 0.8rem;
    font-weight: 700;
    line-height: 1;
}

@media (max-width: 640px) {
    .pl-md.pl-teach-asks-md ul {
        grid-template-columns: 1fr;
    }
}

/* Common Questions: the sanitized HTML is split on its headings server side into
   .pl-disclosure items (the first open). The intro is whatever the admin wrote above
   the first question; the Q badge marks each summary. */
.pl-teach-faq {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin-top: 0.75rem;
}

.pl-teach-faq__intro {
    margin: 0.5rem 0 0;
    color: var(--hub-text-muted);
}

.pl-teach-faq__badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 6px;
    background: var(--hub-blue-soft);
    color: var(--hub-blue);
    font-size: 0.8125rem;
    font-weight: 700;
    line-height: 1;
}

.pl-teach-faq__answer {
    color: var(--hub-text-muted);
}

/* The no headings fallback: the admin wrote the section without questions, so it
   renders as one open block. */
.pl-md.pl-teach-faq-md h3 {
    margin: 0;
    padding: 0.75rem 0 0.25rem;
    border-top: 1px solid var(--hub-border);
    font-size: 1rem;
    font-weight: 600;
}

.pl-md.pl-teach-faq-md h3:first-child {
    border-top: none;
    padding-top: 0.25rem;
}

.pl-md.pl-teach-faq-md p {
    color: var(--hub-text-muted);
    margin: 0 0 0.5rem;
}

/* ── Disclosure (.pl-disclosure) ──────────────────────────────────────────
   The hub's <details> pattern (FRONTEND.md, Component Library). A bordered
   summary row with a title, an optional hint under it, and a chevron that
   points down when closed and up when open; the body continues the same card.
   Never hide the native marker without this chevron in its place. ── */
.pl-disclosure__summary {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    cursor: pointer;
    list-style: none;
    padding: 0.85rem 1rem;
    border: 1px solid var(--hub-border);
    border-radius: 10px;
    background: var(--hub-surface);
    color: var(--hub-text);
    transition: border-color 0.15s ease;
}

.pl-disclosure__summary::-webkit-details-marker {
    display: none;
}

.pl-disclosure__summary::marker {
    content: "";
}

.pl-disclosure__summary:hover,
.pl-disclosure__summary:focus-visible {
    border-color: var(--color-tuscan-yellow);
    outline: none;
}

.pl-disclosure__text {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.pl-disclosure__title {
    flex: 1;
    font-weight: 600;
    color: var(--hub-text);
}

.pl-disclosure__text .pl-disclosure__title {
    flex: 0 0 auto;
}

.pl-disclosure__hint {
    display: block;
    margin-top: 0.15rem;
    font-size: 0.8125rem;
    font-weight: 400;
    color: var(--hub-text-muted);
}

.pl-disclosure__chevron {
    flex: 0 0 auto;
    width: 0.6rem;
    height: 0.6rem;
    margin-right: 0.25rem;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    color: var(--hub-text-muted);
    transform: rotate(45deg);
    transition: transform 0.2s ease;
}

.pl-disclosure[open] > .pl-disclosure__summary .pl-disclosure__chevron {
    transform: rotate(-135deg);
}

.pl-disclosure[open] > .pl-disclosure__summary {
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
}

.pl-disclosure__body {
    padding: 1rem;
    border: 1px solid var(--hub-border);
    border-top: 0;
    border-radius: 0 0 10px 10px;
}

/* The hosting guide: the shared disclosure with the page icon in front of the title. */
.pl-teach-guide__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 0.6rem;
    background: rgba(238, 180, 75, 0.12);
    color: var(--color-tuscan-yellow);
}

/* ── Where the Money Goes ─────────────────────────────────────────────────
   A proportional bar over three tiles, each tile topped in its segment's color
   so the bar and the tiles read as one figure. The flex-basis of each segment
   is inline in the template because it is data. Navy on gold, cream on blue,
   and the theme aware --pl-split-guild-* pair for the guild's green. ── */
.pl-teach-split__note {
    margin: 0 0 1rem;
    color: var(--hub-text-muted);
}

.pl-teach-split__bar {
    display: flex;
    width: 100%;
    height: 2.25rem;
    border-radius: 999px;
    overflow: hidden;
}

.pl-teach-split__seg {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    min-width: 0;
    font-size: 0.8125rem;
    font-weight: 700;
    white-space: nowrap;
    overflow: hidden;
}

.pl-teach-split__seg--slim {
    font-size: 0;
}

.pl-teach-split__seg--you {
    background: var(--color-tuscan-yellow);
    color: var(--color-navy);
}

.pl-teach-split__seg--space {
    background: var(--hub-blue);
    color: var(--color-cream);
}

.pl-teach-split__seg--guild {
    background: var(--pl-split-guild-bg);
    color: var(--pl-split-guild-fg);
}

.pl-teach-split__tiles {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0.75rem;
    margin-top: 1rem;
}

.pl-teach-split__tile {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    padding: 0.85rem 1rem;
    background: var(--hub-surface);
    border: 1px solid var(--hub-border);
    border-top: 4px solid var(--hub-border);
    border-radius: 10px;
}

.pl-teach-split__tile--you { border-top-color: var(--color-tuscan-yellow); }
.pl-teach-split__tile--space { border-top-color: var(--hub-blue); }
.pl-teach-split__tile--guild { border-top-color: var(--pl-split-guild-bg); }

.pl-teach-split__pct {
    font-family: 'Lato', sans-serif;
    font-size: 1.5rem;
    font-weight: 900;
    line-height: 1.1;
    color: var(--hub-text);
}

.pl-teach-split__who {
    font-weight: 700;
    color: var(--hub-text);
}

.pl-teach-split__what {
    font-size: 0.875rem;
    line-height: 1.4;
    color: var(--hub-text-muted);
}

@media (max-width: 640px) {
    .pl-teach-split__tiles {
        grid-template-columns: 1fr;
    }
}

/* Apply card. Its button clears the paragraph above it (Rule 18). */
.pl-teach-apply {
    text-align: center;
}

.pl-teach-apply .pl-btn {
    margin-top: 1rem;
}

.pl-teach-apply__footnote {
    margin: 1.5rem 0 0;
    color: var(--hub-text-muted);
    font-size: 0.8125rem;
}

@media (max-width: 480px) {
    .pl-teach-hero__actions .pl-btn,
    .pl-teach-apply .pl-btn {
        width: 100%;
        text-align: center;
    }
}

/* The Teaching Marketing Page under Class Settings: the heading, its "?" bubble and
   the View the Page link on one row, then the form's section titles and the three
   percentage inputs side by side. */
.pl-teach-page-settings__head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
    margin-bottom: 0.25rem;
}

.pl-teach-page-settings__title {
    margin: 0;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}

.pl-teach-page-settings__intro {
    margin: 0 0 1.25rem;
    color: var(--hub-text-muted);
    font-size: 0.875rem;
}

.pl-teach-page-settings__section {
    margin: 1.75rem 0 0.75rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--hub-border);
    font-size: 1.05rem;
    color: var(--color-tuscan-yellow);
}

.pl-teach-page-settings__section:first-of-type {
    margin-top: 0.5rem;
    padding-top: 0;
    border-top: 0;
}

.pl-teach-page-settings__actions {
    margin-top: 1.5rem;
}

.pl-teach-split-inputs {
    display: flex;
    gap: 1rem;
    flex-wrap: wrap;
}

.pl-teach-split-inputs > .pl-form-group {
    flex: 1 1 8rem;
}

/* ========================================
   Meetings workspace (.pl-meeting-*)
   Spec: docs/superpowers/plans/2026-08-11-meetings.md §6.3
   Theme tokens only — verified on Obsidian + Slate.
   ======================================== */

.pl-meeting-workspace {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
    max-width: 900px;
    width: 100%;
    margin-inline: auto;
}

/* --- Header row --- */
.pl-meeting-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 1rem;
    flex-wrap: wrap;
}
.pl-meeting-breadcrumb {
    display: inline-block;
    margin-bottom: 0.5rem;
    font-size: 0.8125rem;
    color: var(--hub-text-muted);
    text-decoration: none;
}
.pl-meeting-breadcrumb:hover { color: var(--hub-link); }
.pl-meeting-title { margin: 0; }
.pl-meeting-header__actions {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
}
.pl-meeting-print {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    border: 1px solid var(--hub-border-strong);
}
.pl-meeting-print svg { flex-shrink: 0; }

/* --- Savestate pill (§5.2 feedback) --- */
.pl-meeting-savestate {
    padding: 0.25rem 0.75rem;
    border-radius: 999px;
    border: 1px solid var(--hub-border-strong);
    background: var(--hub-elevated);
    font-size: 0.8125rem;
    color: var(--hub-text-muted);
    white-space: nowrap;
}
.pl-meeting-savestate--saving {
    color: var(--hub-text);
    animation: pl-meeting-pulse 1.2s ease-in-out infinite;
}
.pl-meeting-savestate--saved {
    color: var(--color-success, #38a169);
    border-color: var(--color-success, #38a169);
}
.pl-meeting-savestate--error {
    color: var(--color-error);
    border-color: var(--color-error);
    background: var(--color-error-bg);
}
@keyframes pl-meeting-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.45; }
}

/* --- Workspace-level delete confirm dialog --- */
.pl-confirm-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
}
.pl-confirm-dialog {
    background: var(--hub-surface);
    border: 1px solid var(--hub-border);
    border-radius: 0.5rem;
    padding: 1.5rem;
    max-width: 400px;
    width: 90%;
}
.pl-confirm-dialog__title {
    font-size: 1rem;
    font-weight: 600;
    margin: 0 0 0.5rem;
    color: var(--hub-text);
}
.pl-confirm-dialog__message {
    color: var(--hub-text-muted);
    font-size: 0.875rem;
    margin: 0 0 1.25rem;
}
.pl-confirm-dialog__actions {
    display: flex;
    gap: 0.5rem;
    justify-content: flex-end;
}

/* --- Focus-mode dimming: opacity via class, never inline (§6.3) --- */
.pl-meeting-dimmed {
    opacity: 0.3;
    transition: opacity 0.15s ease;
    pointer-events: auto;
}

/* --- Facts strip ---
   Every fact is a label-above-control column; labels share one style and
   controls share one 2.5rem height so the whole row sits level. */
.pl-meeting-facts {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 1rem 1.5rem;
    padding: 1.5rem;
}
.pl-meeting-fact {
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
    margin: 0;
}
/* One label style for every fact — overrides the default .hub-form-group label. */
.pl-meeting-facts .pl-meeting-fact label,
.pl-meeting-fact__label {
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--hub-text-muted);
    margin: 0;
}
/* One control height for every fact. */
.pl-meeting-facts input[type="date"],
.pl-meeting-facts input[type="text"],
.pl-meeting-facts input[type="url"],
.pl-meeting-facts select {
    height: 2.5rem;
    box-sizing: border-box;
}
.pl-meeting-fact__control {
    display: flex;
    align-items: center;
    height: 2.5rem;
}
.pl-meeting-fact--special { min-width: 7.5rem; }
.pl-meeting-special-name { min-width: 180px; }
.pl-meeting-facts input[type="date"] { min-width: 150px; }
.pl-meeting-facts select { min-width: 130px; }
.pl-meeting-fact--video { flex: 1 1 300px; }
.pl-meeting-fact--static { font-size: 0.9375rem; }
/* Rule 14: the native date picker icon is black by default — invisible on Obsidian. */
.pl-meeting-date::-webkit-calendar-picker-indicator { filter: invert(1); cursor: pointer; }
[data-theme="light"] .pl-meeting-date::-webkit-calendar-picker-indicator { filter: none; }
.pl-meeting-video-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
}
.pl-meeting-video-row input[type="url"] { flex: 1 1 240px; min-width: 0; }

/* --- Attachments --- */
.pl-meeting-attachments { padding: 1.5rem; }
.pl-meeting-attachment-list {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
}
.pl-meeting-attachment {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}
.pl-meeting-attachment a { color: var(--hub-link); }
.pl-meeting-attachments__empty { font-size: 0.875rem; margin: 0 0 0.75rem; }
.pl-meeting-attach-btn { margin-top: 0.25rem; }

/* --- Notes cards + read-only prose --- */
.pl-meeting-notes { padding: 1.5rem; }
.pl-meeting-prose { font-size: 0.9375rem; line-height: 1.6; }
.pl-meeting-prose a { color: var(--hub-link); }

/* --- Agenda: the focus-mode accordion --- */
.pl-meeting-agenda { display: flex; flex-direction: column; gap: 0.75rem; }
.pl-meeting-item-list { display: flex; flex-direction: column; gap: 0.5rem; }
/* Empty-state line hides itself the moment real rows exist (HTMX appends included). */
.pl-meeting-empty { font-size: 0.875rem; margin: 0; }
.pl-meeting-empty:not(:only-child) { display: none; }
.pl-meeting-item {
    background: var(--hub-card-bg);
    border: 1px solid var(--hub-card-border);
    border-radius: 8px;
}
.pl-meeting-item__row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.75rem 1rem;
    min-height: 44px;
    cursor: pointer;
}
.pl-meeting-item--open { border-color: var(--hub-border-strong); }
.pl-meeting-item--open .pl-meeting-item__row { cursor: default; }
.pl-meeting-item__chevrons { display: flex; flex-direction: column; gap: 0.25rem; }
.pl-meeting-chevron {
    background: transparent;
    border: none;
    color: var(--hub-text-muted);
    font-size: 0.625rem;
    line-height: 1;
    padding: 0.125rem 0.25rem;
    cursor: pointer;
}
.pl-meeting-chevron:hover { color: var(--hub-text); }
.pl-meeting-item__name { flex: 1; font-weight: 600; font-size: 0.9375rem; }
.pl-meeting-badge {
    display: inline-block;
    padding: 0.125rem 0.5rem;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 700;
    white-space: nowrap;
}
.pl-meeting-badge--actions {
    color: var(--color-navy);
    background: var(--color-tuscan-yellow);
}
.pl-meeting-badge--draft {
    color: var(--hub-text-muted);
    background: var(--hub-surface);
    border: 1px solid var(--hub-border-strong);
}
/* The single Published treatment site-wide — Draft (muted) / Published (blue) /
   Approved (green) read as a progression in both themes. */
.pl-meeting-badge--published {
    color: var(--hub-blue);
    background: transparent;
    border: 1px solid var(--hub-blue);
}
.pl-meeting-badge--approved {
    color: var(--color-success);
    background: var(--color-success-bg);
}
.pl-meeting-item__body { padding: 0.25rem 1rem 1rem; }
.pl-meeting-item__description { font-size: 0.9375rem; margin: 0 0 0.75rem; white-space: pre-line; }
.pl-meeting-credit { font-size: 0.8125rem; margin: 0.5rem 0; }
.pl-meeting-item__footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
    margin-top: 0.75rem;
}
.pl-meeting-minutes-wrap {
    background: var(--hub-input-bg);
    border: 1px solid var(--hub-input-border);
    border-radius: 6px;
}
.pl-meeting-add-item-form {
    display: flex;
    gap: 0.5rem;
    align-items: center;
}
.pl-meeting-add-item-input {
    flex: 1;
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--hub-border-strong);
    border-radius: 6px;
    background: var(--hub-input-bg, var(--hub-card-bg));
    color: var(--hub-text);
    font-size: 0.9375rem;
}
.pl-meeting-add-item-input:focus { outline: none; border-color: var(--hub-link); }

/* --- Item row actions (upvote + edit + trash) --- */
.pl-meeting-item__row-actions {
    display: flex;
    align-items: center;
    gap: 0.15rem;
    margin-left: auto;
    flex-shrink: 0;
}
.pl-meeting-item__icon-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    padding: 0;
    background: transparent;
    border: none;
    color: var(--hub-text-muted);
    cursor: pointer;
    border-radius: 6px;
}
.pl-meeting-item__icon-btn svg { width: 1rem; height: 1rem; }
.pl-meeting-item__icon-btn:hover { color: var(--hub-link); background: var(--hub-hover-bg); }
.pl-meeting-item__icon-btn--danger:hover { color: var(--color-error, #e53e3e); background: var(--hub-hover-bg); }
.pl-meeting-item__upvote-btn {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.2rem 0.4rem;
    background: transparent;
    border: 1px solid transparent;
    color: var(--hub-text-muted);
    font-size: 0.8rem;
    cursor: pointer;
    border-radius: 6px;
}
.pl-meeting-item__upvote-btn svg { width: 0.9rem; height: 0.9rem; }
.pl-meeting-item__upvote-btn:hover { color: var(--hub-link); border-color: var(--hub-border); }
.pl-meeting-item__upvote-btn--active { color: var(--hub-link); border-color: var(--hub-link); }
/* Locked (approved) minutes: the +1 tally stays visible as a read-only record, not a control. */
.pl-meeting-item__upvote-btn--static { cursor: default; }
.pl-meeting-item__upvote-btn--static:hover { color: var(--hub-text-muted); border-color: transparent; }
.pl-meeting-item__upvote-count { font-weight: 600; }

/* --- Action items --- */
.pl-meeting-actions {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin-top: 0.75rem;
}
.pl-meeting-action {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}
.pl-meeting-action__name { flex: 1; }
.pl-meeting-action--done .pl-meeting-action__name {
    text-decoration: line-through;
    color: var(--hub-text-muted);
}
/* Restyled native checkbox — a data value, not a settings toggle (§6.3). */
.pl-meeting-check { position: relative; display: inline-flex; cursor: pointer; }
.pl-meeting-check input {
    position: absolute;
    opacity: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    cursor: pointer;
}
.pl-meeting-check__box {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    border: 1px solid var(--hub-border-strong);
    border-radius: 4px;
    background: var(--hub-input-bg);
    color: var(--color-navy);
    font-size: 0.75rem;
    line-height: 1;
}
.pl-meeting-check input:checked + .pl-meeting-check__box {
    background: var(--color-tuscan-yellow);
    border-color: var(--color-tuscan-yellow);
}
.pl-meeting-check input:checked + .pl-meeting-check__box::after { content: "✓"; font-weight: 700; }
.pl-meeting-check input:focus-visible + .pl-meeting-check__box { outline: 2px solid var(--hub-blue); outline-offset: 1px; }
.pl-meeting-check--static {
    width: 18px;
    text-align: center;
    color: var(--color-success);
    font-weight: 700;
}
.pl-meeting-flag {
    background: transparent;
    border: none;
    color: var(--hub-text-muted);
    font-size: 1rem;
    line-height: 1;
    padding: 0.25rem;
    cursor: pointer;
}
.pl-meeting-flag--on { color: #ef4444; }
.pl-meeting-flag--static { cursor: default; }
.pl-meeting-row-delete {
    background: transparent;
    border: none;
    color: var(--hub-text-muted);
    font-size: 1.125rem;
    line-height: 1;
    padding: 0.25rem 0.5rem;
    cursor: pointer;
}
.pl-meeting-row-delete:hover { color: var(--color-error); }

/* --- Attendance --- */
.pl-meeting-attendance { padding: 1.5rem; }
.pl-meeting-attendee-list {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin-bottom: 1rem;
}
.pl-meeting-attendee {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.9375rem;
}
.pl-meeting-attendee__name { flex: 1; }
.pl-meeting-attendee__name-input { flex: 1; }
.pl-meeting-attendee--absent .pl-meeting-attendee__name,
.pl-meeting-attendee--absent .pl-meeting-attendee__name-input {
    text-decoration: line-through;
    color: var(--hub-text-muted);
}
.pl-meeting-attendee-picker {
    display: flex;
    gap: 1rem 1.5rem;
    flex-wrap: wrap;
}
/* Controls and buttons share one height so the add row sits level. */
.pl-meeting-picker-group select,
.pl-meeting-picker-group input[type="text"],
.pl-meeting-picker-group .pl-btn {
    height: 2.5rem;
    box-sizing: border-box;
}
.pl-meeting-picker-group {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0;
}

/* --- Attention / approved tints (home strip + locked banner) --- */
.pl-meeting-attention { border-left: 3px solid var(--color-tuscan-yellow); }
.pl-meeting-approved {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    padding: 0.75rem 1rem;
    border-radius: 8px;
    background: var(--color-success-bg);
    color: var(--color-success);
    font-size: 0.9375rem;
}

/* --- Carryover panel (open action items from earlier meetings) --- */
.pl-meeting-carryover {
    padding: 1.5rem;
    border-left: 3px solid var(--color-tuscan-yellow);
}
.pl-meeting-carryover__group { margin-top: 0.75rem; }
.pl-meeting-carryover__source { font-size: 0.8125rem; margin: 0 0 0.5rem; }
.pl-meeting-carryover__row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.375rem 0;
}
.pl-meeting-carryover__name { flex: 1; font-size: 0.9375rem; }
.pl-meeting-carryover__actions { display: flex; gap: 0.5rem; }

/* --- Pending proposals review strip + the member "Your proposals" block --- */
.pl-meeting-proposals { padding: 1.5rem; }
.pl-meeting-proposal {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    padding: 0.625rem 0;
    border-top: 1px solid var(--hub-border);
}
.pl-meeting-proposal__info { flex: 1; min-width: 220px; }
.pl-meeting-proposal__title { font-weight: 600; font-size: 0.9375rem; margin-right: 0.5rem; }
.pl-meeting-proposal__by { font-size: 0.8125rem; }
.pl-meeting-proposal__why { font-size: 0.8125rem; margin: 0.25rem 0 0; white-space: pre-line; }
.pl-meeting-proposal__actions { display: flex; gap: 0.5rem; }
.pl-meeting-decide__intro { margin: 0 0 1rem; font-size: 0.875rem; }
.pl-meeting-myprops { padding: 1.5rem; }
.pl-meeting-myprop {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
    padding: 0.375rem 0;
}
.pl-meeting-myprop__title { font-size: 0.9375rem; }
.pl-meeting-myprop__link { color: var(--hub-link); font-size: 0.875rem; }
.pl-meeting-myprop__note { flex-basis: 100%; font-size: 0.8125rem; margin: 0; }
.pl-meeting-propose { margin-top: 0.25rem; }

/* --- Footer: Approve minutes / Delete meeting (rule 18 — clear of the card above) --- */
.pl-meeting-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-top: 1.5rem;
}

/* --- Row-level busy pulse while an HTMX request is in flight --- */
.pl-meeting-workspace .htmx-request { opacity: 0.6; }

/* --- The workspace calendar block (spec §6.3) --- */
.pl-meeting-calendar {
    display: flex;
    flex-direction: column;
    align-items: flex-start; /* buttons keep their natural width — no full-row stretch */
    gap: 0.5rem;
    flex-basis: 100%;
    padding-top: 0.75rem;
    border-top: 1px solid var(--hub-border);
}
.pl-meeting-calendar__line { font-size: 0.875rem; color: var(--color-success); }
.pl-meeting-calendar__line a { color: var(--hub-link); }
.pl-meeting-calendar__warn {
    font-size: 0.8125rem;
    color: var(--hub-link);
    border-left: 3px solid var(--color-tuscan-yellow);
    padding-left: 0.5rem;
}
.pl-meeting-calendar__unlink {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
}
.pl-meeting-calendar__hint { font-size: 0.8125rem; }
.pl-meeting-calendar-create { width: 100%; }
.pl-meeting-calendar-or {
    text-align: center;
    font-size: 0.8125rem;
    margin: 1rem 0 0.75rem;
}

/* --- The Meetings home (spec §6.2) --- */
.pl-meeting-home-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1.5rem;
}
.pl-meeting-home-header__lead { margin: 0.5rem 0 0; max-width: 65ch; }
.pl-meeting-zone { padding: 1.5rem; margin-bottom: 1.5rem; }
.pl-meeting-zone__empty { font-size: 0.875rem; margin: 0; }
.pl-meeting-up {
    padding: 0.625rem 0;
    border-top: 1px solid var(--hub-border);
}
.pl-meeting-up:first-of-type { border-top: none; }
.pl-meeting-up__main {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
}
.pl-meeting-up__title { font-weight: 600; color: var(--hub-text); }
.pl-meeting-up__title:hover { color: var(--hub-link); }
.pl-meeting-up__meta { font-size: 0.8125rem; margin-top: 0.25rem; }

/* Needs-attention strip: the carryover panel's amber-left-border idiom. */
.pl-meeting-attention { border-left: 3px solid var(--color-tuscan-yellow); }
.pl-meeting-attention__row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
    padding: 0.375rem 0;
    text-decoration: none;
    color: var(--hub-text);
    font-size: 0.875rem;
}
.pl-meeting-attention__row:hover .pl-meeting-attention__title { color: var(--hub-link); }
.pl-meeting-attention__title { font-weight: 600; }
.pl-meeting-attention__flag { color: var(--hub-link); font-weight: 600; font-size: 0.8125rem; }
.pl-meeting-attention__start { display: inline-block; }

/* Zone 1 card — the member's list-page "Propose an agenda item" affordance (§6.2 Part 2a). */
.pl-meeting-up__actions { margin-top: 0.5rem; }

/* Lock-time disposition modal — one Carry/Set-aside choice per pending proposal (§6.3). */
.pl-lock-disposition__row { border: none; padding: 0.5rem 0; }
.pl-lock-disposition__title { font-weight: 600; display: block; }
.pl-lock-disposition__option { margin-right: 1rem; font-weight: 400; }

/* Coordinator table — stacks into labeled per-guild cards under 720px (§6.2). */
.pl-meeting-dash { width: 100%; border-collapse: collapse; font-size: 0.875rem; }
.pl-meeting-dash th {
    text-align: left;
    color: var(--hub-text-muted);
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 0.5rem 0.75rem 0.5rem 0;
}
.pl-meeting-dash td {
    padding: 0.5rem 0.75rem 0.5rem 0;
    border-top: 1px solid var(--hub-border);
    vertical-align: top;
}
.pl-meeting-dash td a { color: var(--hub-link); }
.pl-meeting-dash__guild { font-weight: 600; }
.pl-meeting-dash__start { display: inline-block; margin-left: 0.5rem; }
.pl-meeting-tick { color: var(--color-success); font-weight: 700; margin-left: 0.25rem; }
@media (max-width: 720px) {
    .pl-meeting-dash thead { display: none; }
    .pl-meeting-dash tbody tr {
        display: block;
        border: 1px solid var(--hub-border);
        border-radius: 8px;
        padding: 0.75rem;
        margin-bottom: 0.75rem;
        background: var(--hub-surface);
    }
    .pl-meeting-dash td {
        display: block;
        border: none;
        padding: 0.25rem 0;
    }
    .pl-meeting-dash td::before {
        content: attr(data-label);
        display: block;
        color: var(--hub-text-muted);
        font-size: 0.6875rem;
        text-transform: uppercase;
        letter-spacing: 0.04em;
    }
    .pl-meeting-dash__start { margin-left: 0; margin-top: 0.25rem; display: block; }
}

/* Archive filter bar — rule-13 .hub-form-group wrappers, option colors included. */
.pl-meeting-filterbar {
    display: flex;
    align-items: flex-end;
    gap: 0.75rem;
    flex-wrap: wrap;
    margin-bottom: 1rem;
}
.pl-meeting-filterbar .hub-form-group { margin: 0; }
.pl-meeting-filterbar select option {
    background: var(--hub-card-bg);
    color: var(--hub-text);
}
.pl-meeting-filterbar__apply { margin-bottom: 0.25rem; }
.pl-meeting-archive__title { color: var(--hub-text); font-weight: 600; }
.pl-meeting-archive__title:hover { color: var(--hub-link); }

/* --- The guild detail Meetings tab (spec §6.4) --- */
.pl-guild-meetings { display: flex; flex-direction: column; gap: 1rem; }
.pl-guild-meetings__toolbar {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
}
.pl-guild-meetings__pending { text-decoration: none; }
.pl-guild-meetings__card { padding: 1.5rem; }
.pl-guild-meetings__title { font-weight: 600; font-size: 1.05rem; color: var(--hub-text); }
.pl-guild-meetings__title:hover { color: var(--hub-link); }
.pl-guild-meetings__meta { font-size: 0.875rem; margin-top: 0.25rem; }
.pl-guild-meetings__join { margin-top: 0.75rem; }
.pl-guild-meetings__propose { margin-top: 1rem; }
.pl-guild-meetings__hint { font-size: 0.875rem; margin-top: 0.75rem; }
.pl-guild-meetings__start { margin-top: 0.75rem; }
.pl-guild-meetings__minute {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
    padding: 0.375rem 0;
    font-size: 0.9375rem;
}
.pl-guild-meetings__minute a { color: var(--hub-text); font-weight: 600; }
.pl-guild-meetings__minute a:hover { color: var(--hub-link); }
.pl-guild-meetings__archive-link {
    display: inline-block;
    margin-top: 0.75rem;
    color: var(--hub-link);
    font-size: 0.875rem;
}

/* --- Mobile --- */
@media (max-width: 480px) {
    .pl-meeting-action { flex-wrap: wrap; }
    .pl-meeting-action__name { flex-basis: 100%; order: -1; }
    .pl-meeting-picker-group { flex-wrap: wrap; }
    .pl-meeting-video-row input[type="url"] { min-width: 0; width: 100%; }
}

/* --- Print: the workspace IS the export (spec §6.3 — window.print()) --- */
@media print {
    .hub-sidebar,
    .hub-topbar,
    .pl-meeting-header__actions,
    .pl-meeting-breadcrumb,
    .pl-meeting-item__chevrons,
    .pl-meeting-add-item-form,
    .pl-meeting-attach-btn,
    .pl-meeting-item__footer,
    .pl-meeting-row-delete,
    .pl-meeting-flag:not(.pl-meeting-flag--on),
    .pl-meeting-attendee-picker,
    .pl-meeting-calendar,
    .pl-meeting-carryover,
    .pl-meeting-proposals,
    .pl-meeting-myprops,
    .pl-meeting-propose,
    .pl-meeting-footer,
    .pl-meeting-approved .pl-btn,
    .ql-toolbar {
        display: none !important;
    }
    body, .hub-main, .hub-content { background: #fff !important; color: #000 !important; }
    .pl-meeting-workspace { max-width: none; color: #000; }
    .pl-meeting-workspace .hub-card,
    .pl-meeting-item {
        background: #fff !important;
        border-color: #ccc !important;
        color: #000 !important;
        box-shadow: none !important;
    }
    /* Force every accordion body visible — overrides Alpine's inline display:none. */
    .pl-meeting-item__body { display: block !important; }
    /* Undim everything. */
    .pl-meeting-dimmed { opacity: 1 !important; }
    .pl-meeting-workspace input,
    .pl-meeting-workspace select,
    .pl-meeting-workspace textarea,
    .pl-meeting-minutes-wrap,
    .ql-container {
        background: #fff !important;
        border: none !important;
        color: #000 !important;
        appearance: none;
        padding: 0;
    }
    .pl-meeting-title, .pl-meeting-fact, .pl-meeting-item__name, .pl-meeting-prose { color: #000 !important; }
    .pl-meeting-savestate { display: none !important; }
}

/* --- Form footer action row (Save / Cancel left, Delete pushed right) ------- */
.pl-form-actions {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 1rem;
    row-gap: 0.75rem;
}
.pl-form-actions__danger {
    margin-left: auto;
}

/* --- Paid orientations ------------------------------------------------------ */
/* Price chip shown beside orientation headings, on paid dashboard rows, and on
   the respond screen's Paid indicator. Tokens only — themes for free. */
.pl-price-chip {
    display: inline-block;
    padding: 0.15rem 0.55rem;
    background: var(--hub-surface);
    color: var(--color-tuscan-yellow);
    border: 1px solid var(--hub-border);
    border-radius: 6px;
    font-size: 0.8rem;
    font-weight: 700;
    white-space: nowrap;
}
.pl-price-chip--ok {
    color: #7bdcb5;
}
.pl-price-chip--danger {
    color: #e05d5d;
}
/* The refund-consequence one-liner above Decline/Cancel controls. */
.pl-refund-note {
    margin: 0 0 0.5rem;
    font-size: 0.85rem;
    color: var(--hub-text-muted);
}
/* Full-width failed-refund alert card on the respond screen. */
.pl-refund-failed-banner {
    border: 1px solid rgba(224, 93, 93, 0.55);
    background: rgba(224, 93, 93, 0.12);
    border-radius: 8px;
    padding: 0.9rem 1.25rem;
    margin-bottom: 1.5rem;
    font-size: 0.95rem;
}
/* Checkout return page: one centered card. */
.pl-checkout-return {
    display: flex;
    justify-content: center;
    padding: 2rem 0;
}
.pl-checkout-return__card {
    max-width: 560px;
    width: 100%;
    padding: 1.5rem;
}
/* Guild-page heading row wraps the chip under the title on phones. */
.pl-orient-heading {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex-wrap: wrap;
    margin: 0 0 0.5rem;
}

/* Floating back-to-top button on the User Settings page (hub-tokenized; deliberately
   NOT the public-CMS #scroll-top-btn styles). z-index sits above page content and the
   sticky topbar but below the modal backdrop (500), so the discard confirm covers it. */
.pl-scroll-top {
    position: fixed;
    bottom: calc(1.25rem + env(safe-area-inset-bottom, 0px));
    right: 1.25rem;
    z-index: 90;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    border: 1px solid var(--hub-border);
    cursor: pointer;
    background: var(--hub-elevated);
    color: var(--color-tuscan-yellow);
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
}
.pl-scroll-top:hover {
    transform: translateY(-2px);
}

/* ── Guild Join / Member hero CTA ────────────────────────────────────────── */
.pl-guild-cta {
    display: inline-flex;
}
.pl-guild-cta__member {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}
.pl-guild-cta__badge {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    cursor: pointer;
}
.pl-guild-cta__caret {
    margin-left: 0.1rem;
    transition: transform 0.15s ease;
}
.pl-guild-cta__caret--open {
    transform: rotate(180deg);
}
.pl-guild-cta__menu {
    position: absolute;
    top: calc(100% + 0.35rem);
    right: 0;
    z-index: 40;
    min-width: 160px;
    padding: 0.35rem;
    border-radius: 8px;
    border: 1px solid var(--hub-border);
    background: var(--hub-elevated);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
}
.pl-guild-cta__menu-item {
    display: block;
    width: 100%;
    padding: 0.55rem 0.75rem;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: var(--hub-text);
    text-align: left;
    font-size: 0.9rem;
    cursor: pointer;
}
.pl-guild-cta__menu-item:hover {
    background: var(--hub-surface);
}

/* ── Guild stat-chips row: chips on the left, Join/Member CTA on the right ──
   Wraps on narrow viewports so the CTA drops under the chips instead of overflowing. */
.pl-guild-statbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 0 0 1rem;
}
.pl-guild-statbar__chips {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
}

/* ── Sticky mini Join CTA (clones .pl-scroll-top placement) ──────────────── */
.pl-guild-join-fab {
    position: fixed;
    bottom: calc(1.25rem + env(safe-area-inset-bottom, 0px));
    right: 1.25rem;
    z-index: 90;
}
.pl-guild-join-fab__pill {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.7rem 1.15rem;
    border-radius: 999px;
    font-size: 0.9rem;
    font-weight: 700;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
    cursor: pointer;
}
.pl-guild-join-fab__pill--join {
    border: 1px solid var(--color-tuscan-yellow);
    background: var(--color-tuscan-yellow);
    color: var(--color-navy);
}
.pl-guild-join-fab__pill--join:hover {
    transform: translateY(-2px);
}
.pl-guild-join-fab__pill--member {
    border: 1px solid var(--hub-border);
    background: var(--hub-elevated);
    color: var(--hub-text-muted);
    cursor: default;
}

/* ── Join-modal benefit rows ─────────────────────────────────────────────── */
.pl-benefit-rows {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}
.pl-benefit-row {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    font-size: 0.92rem;
    color: var(--hub-text);
    line-height: 1.4;
}
.pl-benefit-row svg {
    flex-shrink: 0;
    width: 18px;
    height: 18px;
    margin-top: 0.1rem;
    color: var(--color-tuscan-yellow);
}
.pl-benefit-row a {
    color: var(--color-tuscan-yellow);
}

/* ── "You get this guild's updates" note — top+bottom breathing room (8px grid) so it
   doesn't butt against the confirmation icon above or the "Manage in Settings" button below. */
.pl-guild-updates-note {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.9rem;
    padding: 0.5rem 0;
}

/* ── Member Directory guild badges ───────────────────────────────────────── */
.pl-directory-guilds {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    margin-top: 0.75rem;
}
.pl-directory-guild {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    text-decoration: none;
}
.pl-directory-guild img {
    display: block;
    width: 14px;
    height: 14px;
}

/* Phone clearance: the fixed back-to-top FAB floats over a padded strip, never over the
   page's last row of controls (Guilds toggles, danger-zone footer, Tours Save). */
@media (max-width: 768px) {
    #pl-settings-root {
        padding-bottom: 4.5rem;
    }
}

/* ── Equipment directory (equipment-reservations spec PR 1) ─────────────── */
.pl-equip-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
    gap: 1rem;
}
.pl-equip-card {
    position: relative;
    display: flex;
    flex-direction: column;
    padding: 0;
    overflow: hidden;
}
.pl-equip-card__photo,
.pl-equip-card__placeholder {
    width: 100%;
    height: 140px;
    display: block;
    object-fit: cover;
}
.pl-equip-card__placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--hub-surface);
    color: var(--hub-text-muted);
}
.pl-equip-card__body {
    padding: 0.9rem 1rem 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
/* The name link stretches over the whole card (the tap target); the guild chip
   sits above it with its own link. */
.pl-equip-card__name {
    font-weight: 700;
    color: var(--hub-text);
    text-decoration: none;
}
.pl-equip-card__name::after {
    content: "";
    position: absolute;
    inset: 0;
}
.pl-equip-card__meta {
    display: flex;
    gap: 0.4rem;
    flex-wrap: wrap;
    align-items: center;
    position: relative;
    z-index: 1;
}
.pl-equip-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    font-size: 0.75rem;
    font-weight: 600;
    padding: 0.2rem 0.6rem;
    border-radius: 999px;
}
.pl-equip-badge--ok {
    color: #7bdcb5;
    background: rgba(123, 220, 181, 0.12);
}
[data-theme="light"] .pl-equip-badge--ok {
    color: #1e7a4f;
    background: rgba(30, 122, 79, 0.1);
}
.pl-equip-badge--warn {
    color: var(--color-tuscan-yellow);
    background: rgba(238, 180, 75, 0.14);
}
[data-theme="light"] .pl-equip-badge--warn {
    color: #8a5a00;
    background: rgba(238, 180, 75, 0.18);
}
.pl-equip-badge--muted {
    color: var(--hub-text-muted);
    background: var(--hub-surface);
}

/* Filter row — chips scroll horizontally in their own contained region on phones. */
.pl-equip-filters {
    display: flex;
    gap: 0.75rem 1rem;
    flex-wrap: wrap;
    align-items: center;
    margin-bottom: 1.25rem;
}
.pl-equip-chips {
    display: flex;
    gap: 0.4rem;
    overflow-x: auto;
    max-width: 100%;
    padding-bottom: 0.25rem;
}
.pl-equip-chip {
    white-space: nowrap;
    padding: 0.25rem 0.7rem;
    border-radius: 999px;
    border: 1px solid var(--hub-border);
    color: var(--hub-text-muted);
    background: var(--hub-card-bg);
    text-decoration: none;
    font-size: 0.85rem;
}
.pl-equip-chip--active {
    border-color: var(--color-tuscan-yellow);
    color: var(--hub-text);
}
.pl-equip-search input[type="search"] {
    min-width: 200px;
}

/* Detail page hero + requirements banner. */
.pl-equip-hero {
    padding: 0;
    overflow: hidden;
    margin-bottom: 1.25rem;
}
.pl-equip-hero__photo {
    width: 100%;
    height: 220px;
    object-fit: cover;
    display: block;
}
.pl-equip-hero__body {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    padding: 1.1rem 1.5rem 1.25rem;
}
.pl-equip-hero__titles {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
.pl-equip-banner {
    padding: 1rem 1.5rem;
    margin-bottom: 1.25rem;
    border-left: 4px solid var(--hub-border);
}
.pl-equip-banner--ok {
    border-left-color: #7bdcb5;
}
.pl-equip-banner--warn {
    border-left-color: var(--color-tuscan-yellow);
}
.pl-equip-banner__ok-text {
    color: #7bdcb5;
}
[data-theme="light"] .pl-equip-banner__ok-text {
    color: #1e7a4f;
}
[data-theme="light"] .pl-equip-banner--ok {
    border-left-color: #1e7a4f;
}

/* Manage panel — form card, save row, staff rows; reflows to a column on phones. */
.pl-equip-form-card {
    padding: 1.5rem;
    max-width: 640px;
}
.pl-equip-save-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    justify-content: flex-end;
    margin-top: 1.5rem;
}
.pl-equip-guild-toggle {
    display: block;
}
.pl-equip-staff-list {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin-bottom: 1.25rem;
}
.pl-equip-staff-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    flex-wrap: wrap;
    padding: 0.5rem 0.75rem;
    background: var(--hub-surface);
    border-radius: 6px;
}
.pl-equip-staff-row__who {
    display: flex;
    align-items: center;
    gap: 0.6rem;
}
.pl-equip-staff-add {
    border-top: 1px solid var(--hub-border);
    padding-top: 1.25rem;
}
.pl-equip-staff-add__form {
    display: flex;
    gap: 0.75rem;
    align-items: flex-end;
    flex-wrap: wrap;
}
.pl-equip-staff-add__field {
    flex: 2;
    min-width: 220px;
}

/* Orientation deep-link highlight (?type=<pk> from an equipment requirements banner). */
.pl-orient-type--highlight {
    outline: 2px solid var(--color-tuscan-yellow);
    outline-offset: 6px;
    border-radius: 8px;
}

@media (max-width: 768px) {
    .pl-equip-grid {
        grid-template-columns: 1fr;
    }
    .pl-equip-hero__body {
        flex-direction: column;
    }
    .pl-equip-save-row {
        justify-content: stretch;
    }
    .pl-equip-search input[type="search"] {
        width: 100%;
    }
}

/* ── Equipment reservations (PR 2): schedule strip, timeline, booking, hours ── */
.pl-equip-schedule {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
    margin-bottom: 1.25rem;
}
.pl-equip-schedule.htmx-request {
    opacity: 0.55;
}
.pl-equip-strip__head {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 0.75rem;
}
.pl-equip-strip__nav {
    margin-left: auto;
    display: flex;
    gap: 0.4rem;
}
.pl-equip-strip__spinner {
    width: 14px;
    height: 14px;
    border-radius: 50%;
    border: 2px solid var(--hub-text-muted);
    border-top-color: transparent;
    animation: pl-equip-spin 0.8s linear infinite;
}
.htmx-indicator.pl-equip-strip__spinner {
    opacity: 0;
}
.htmx-request .pl-equip-strip__spinner,
.htmx-request.pl-equip-strip__spinner {
    opacity: 1;
}
@keyframes pl-equip-spin {
    to { transform: rotate(360deg); }
}
/* The day strip scrolls horizontally in its own contained region on phones. */
.pl-equip-strip {
    display: flex;
    gap: 0.4rem;
    overflow-x: auto;
    max-width: 100%;
    padding-bottom: 0.25rem;
}
.pl-equip-day {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.1rem;
    min-width: 3.2rem;
    padding: 0.45rem 0.6rem;
    border-radius: 8px;
    border: 1px solid var(--hub-border);
    background: var(--hub-card-bg);
    color: var(--hub-text);
    cursor: pointer;
}
.pl-equip-day--selected {
    border-color: var(--color-tuscan-yellow);
}
.pl-equip-day--muted {
    color: var(--hub-text-muted);
    background: var(--hub-surface);
    cursor: default;
}
.pl-equip-day__name {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.pl-equip-day__num {
    font-weight: 700;
}
/* Day timeline — a vertical list, never a table (mobile rule). */
.pl-equip-timeline {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}
.pl-equip-slot {
    display: flex;
    gap: 0.75rem;
    flex-wrap: wrap;
    align-items: baseline;
    padding: 0.45rem 0.75rem;
    border-radius: 6px;
    border-left: 3px solid var(--hub-border);
    background: var(--hub-surface);
}
.pl-equip-slot--free {
    border-left-color: #7bdcb5;
}
[data-theme="light"] .pl-equip-slot--free {
    border-left-color: #1e7a4f;
}
.pl-equip-slot--busy {
    border-left-color: var(--color-tuscan-yellow);
}
.pl-equip-slot__when {
    font-weight: 600;
    white-space: nowrap;
}
.pl-equip-slot__label {
    color: var(--hub-text-muted);
}
/* Book a Time — selects stack full width on phones. */
.pl-equip-book-row {
    display: flex;
    gap: 0.75rem;
    flex-wrap: wrap;
    align-items: flex-end;
}
.pl-equip-book-field {
    flex: 1;
    min-width: 130px;
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}
.pl-equip-book-field--wide {
    flex: 2;
    min-width: 200px;
}
/* Reservation lists (detail page + manage panel) — rows wrap into cards on phones. */
.pl-equip-res-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
.pl-equip-res-row {
    display: flex;
    gap: 0.5rem 1rem;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    padding: 0.5rem 0.75rem;
    background: var(--hub-surface);
    border-radius: 6px;
}
/* Index card availability line. */
.pl-equip-avail {
    font-size: 0.8125rem;
}
.pl-equip-avail--free {
    color: #7bdcb5;
}
[data-theme="light"] .pl-equip-avail--free {
    color: #1e7a4f;
}
.pl-equip-avail--busy {
    color: var(--color-tuscan-yellow);
}
[data-theme="light"] .pl-equip-avail--busy {
    color: #8a5a00;
}
.pl-equip-avail--closed {
    color: #e06c5c;
}
.pl-equip-avail--muted {
    color: var(--hub-text-muted);
}
/* Manage panel hours rows. */
.pl-equip-hours-rows {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}
.pl-equip-hours-row {
    padding: 1rem;
    background: var(--hub-surface);
}
.pl-equip-hours-row__fields {
    display: flex;
    gap: 0.75rem;
    flex-wrap: wrap;
}
.pl-equip-hours-row__field {
    flex: 1;
    min-width: 110px;
}

/* ── Equipment hours window editor: compact day-pill checkboxes ── */
.pl-equip-days ul {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    padding: 0;
    margin: 0.25rem 0 0;
}
.pl-equip-days li label {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    /* min-height keeps the pill a real mobile tap target (44px guideline). */
    min-height: 2.75rem;
    padding: 0.25rem 0.85rem;
    border: 1px solid var(--hub-border);
    border-radius: 999px;
    background: var(--hub-card-bg);
    color: var(--hub-text);
    font-size: 0.85rem;
    cursor: pointer;
}
.pl-equip-days li label:has(input:checked) {
    border-color: var(--color-tuscan-yellow);
}
.pl-equip-days input[type="checkbox"] {
    accent-color: var(--color-tuscan-yellow);
    margin: 0;
}

/* ── Equipment-owned orientations ── */
.pl-equip-orientation {
    margin-bottom: 1.25rem;
    scroll-margin-top: 1rem;
}
.pl-orient-confirmed {
    color: #7bdcb5;
}
[data-theme="light"] .pl-orient-confirmed {
    color: #1e7a4f;
}
.pl-equip-slot-group {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}
/* Attendee sub-rows under an Upcoming Slots row — indented, whole row links to respond. */
.pl-equip-attendee-row {
    display: flex;
    gap: 0.6rem;
    align-items: center;
    flex-wrap: wrap;
    margin-left: 1.25rem;
    padding: 0.35rem 0.75rem;
    border-radius: 6px;
    background: var(--hub-card-bg);
    border: 1px solid var(--hub-border);
    color: var(--hub-text);
    text-decoration: none;
    font-size: 0.9rem;
}

/* ── Orientations on the reservation schedule (equipment-orientation-hours PR 2) ── */
.pl-equip-slot--orientation {
    border-left-color: var(--hub-blue);
}
.pl-equip-slot--orientation .pl-equip-slot__label {
    color: var(--hub-blue);
}
.pl-equip-timeline__note {
    margin: 0.5rem 0 0;
    font-size: 0.8125rem;
}
/* An Upcoming Slots row sitting under a confirmed reservation: muted, never offered to members. */
.pl-equip-res-row--blocked {
    opacity: 0.65;
}
.pl-equip-res-row__blocked {
    display: block;
    color: var(--hub-text-muted);
    font-size: 0.8125rem;
}

/* ========================================
   Class lifecycle (class-lifecycle spec PR 1)
   One badge for every class state, the review pipeline strip, the reviewer
   note block, the readiness checklist, and the list facet chips. Theme tokens
   only: the --pl-lifecycle-* tones are defined on :root and [data-theme="light"]
   at the top of this file.
   ======================================== */
.pl-lifecycle-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    font-size: 0.72rem;
    font-weight: 700;
    padding: 0.18rem 0.6rem;
    border-radius: 999px;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    white-space: nowrap;
    background: rgba(139, 151, 168, 0.18);
    color: var(--hub-text-muted);
}
.pl-lifecycle-badge--awaiting_guild_lead,
.pl-lifecycle-badge--awaiting_admin {
    background: rgba(238, 180, 75, 0.16);
    color: var(--pl-lifecycle-review);
}
.pl-lifecycle-badge--changes_requested {
    background: var(--hub-blue-soft);
    color: var(--hub-blue);
}
.pl-lifecycle-badge--upcoming {
    background: var(--color-success-bg);
    color: var(--pl-lifecycle-live);
}
.pl-lifecycle-badge--completed {
    background: rgba(123, 200, 143, 0.08);
    color: var(--hub-text-muted);
}
.pl-lifecycle-badge--cancelled {
    background: var(--color-error-bg);
    color: var(--pl-lifecycle-cancelled);
}
/* "Sale: 20% off" on the manage class header, composed onto the badge beside it. */
.pl-sale-pill {
    background: var(--color-error-bg);
    color: var(--pl-lifecycle-cancelled);
}
.pl-lifecycle-badge .pl-help {
    text-transform: none;
    letter-spacing: 0;
    font-weight: 400;
}

/* Review pipeline strip: circles joined by a track that fills to the current step. */
.pl-pipeline {
    position: relative;
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 0.5rem;
    margin: 0.75rem 0 0.5rem;
    padding: 0;
    list-style: none;
}
.pl-pipeline__track {
    position: absolute;
    top: 0.9rem;
    left: 0.9rem;
    right: 0.9rem;
    height: 3px;
    background: var(--hub-border);
    border-radius: 2px;
}
.pl-pipeline__fill {
    height: 100%;
    background: var(--pl-lifecycle-live);
    border-radius: 2px;
}
.pl-pipeline--bounced .pl-pipeline__fill {
    background: var(--hub-blue);
}
.pl-pipeline__step {
    position: relative;
    z-index: 1;
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.35rem;
    min-width: 0;
    text-align: center;
}
.pl-pipeline__dot {
    box-sizing: border-box;
    width: 1.8rem;
    height: 1.8rem;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.85rem;
    font-weight: 700;
    background: var(--hub-card-bg);
    border: 2px solid var(--hub-border);
    color: var(--hub-text-muted);
}
.pl-pipeline__step--done .pl-pipeline__dot {
    background: var(--pl-lifecycle-live);
    border-color: var(--pl-lifecycle-live);
    color: var(--pl-lifecycle-live-contrast);
}
.pl-pipeline__step--current .pl-pipeline__dot {
    border-color: var(--color-tuscan-yellow);
    color: var(--pl-lifecycle-review);
    box-shadow: 0 0 0 4px rgba(238, 180, 75, 0.22);
}
.pl-pipeline__step--changes_requested .pl-pipeline__dot {
    background: var(--hub-blue);
    border-color: var(--hub-blue);
    color: #fff;
}
.pl-pipeline__label {
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--hub-text-muted);
    line-height: 1.2;
}
.pl-pipeline__step--done .pl-pipeline__label,
.pl-pipeline__step--current .pl-pipeline__label {
    color: var(--hub-text);
}
.pl-pipeline__step--changes_requested .pl-pipeline__label {
    color: var(--hub-blue);
}
.pl-pipeline__detail {
    font-size: 0.7rem;
    color: var(--hub-text-muted);
}
.pl-pipeline--muted {
    opacity: 0.55;
}
.pl-pipeline__headline {
    margin: 0;
    font-weight: 700;
    color: var(--hub-text);
}
.pl-pipeline__headline--muted {
    color: var(--hub-text-muted);
}
@media (max-width: 480px) {
    .pl-pipeline {
        flex-direction: column;
        align-items: stretch;
        gap: 0.9rem;
        padding-left: 0;
    }
    .pl-pipeline__track {
        top: 0.9rem;
        bottom: 0.9rem;
        left: 0.8rem;
        right: auto;
        width: 3px;
        height: auto;
    }
    .pl-pipeline__fill {
        width: 100%;
        height: var(--pl-pipeline-fill, 0%);
    }
    .pl-pipeline__step {
        flex-direction: row;
        align-items: center;
        text-align: left;
        gap: 0.75rem;
    }
}

/* Reviewer's note on a bounced class, on the edit page and workspace overview. */
.pl-review-note {
    margin: 0.75rem 0 0;
    padding: 0.75rem 1rem;
    border-left: 3px solid var(--color-tuscan-yellow);
    background: rgba(238, 180, 75, 0.08);
    border-radius: 0 6px 6px 0;
    white-space: pre-wrap;
    color: var(--hub-text);
}
.pl-review-note__label {
    display: block;
    margin-bottom: 0.25rem;
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--hub-text-muted);
}

/* Readiness checklist: the five things a class needs before it can be submitted. */
.pl-readiness {
    list-style: none;
    margin: 0.5rem 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}
.pl-readiness__item {
    display: flex;
    align-items: baseline;
    gap: 0.6rem;
    font-size: 0.9rem;
}
.pl-readiness__mark {
    flex: 0 0 1.25rem;
    font-weight: 700;
    text-align: center;
    color: var(--hub-text-muted);
}
.pl-readiness__item--ok .pl-readiness__mark {
    color: var(--pl-lifecycle-live);
}
.pl-readiness__item--todo .pl-readiness__mark {
    color: var(--pl-lifecycle-cancelled);
}
.pl-readiness__hint {
    color: var(--hub-text-muted);
}
.pl-readiness__item--ok .pl-readiness__hint {
    display: none;
}
/* Grid variant (opt in with grid=True) for full width cards like the class review page,
   where five short items stacked in one column wasted most of the row. */
.pl-readiness--grid .pl-readiness__item {
    align-items: flex-start;
    padding: 0.55rem 0.75rem;
    border: 1px solid var(--hub-card-border);
    border-radius: 8px;
    background: var(--hub-bg);
}
.pl-readiness--grid .pl-readiness__item--todo {
    border-color: var(--pl-lifecycle-cancelled);
}
.pl-readiness--grid .pl-readiness__label {
    font-weight: 600;
}
.pl-readiness--grid .pl-readiness__hint {
    display: block;
    font-size: 0.8125rem;
    margin-top: 0.15rem;
}
@media (min-width: 720px) {
    .pl-readiness--grid {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
        gap: 0.5rem;
    }
}

/* Class review "Class Details" list. Was an inline 140px grid that forced a narrow
   label column on phones; the labels now stack above their values below 640px. */
.pl-review-details {
    display: grid;
    grid-template-columns: 140px 1fr;
    gap: 10px 18px;
    font-size: 14px;
    margin: 0 0 1.5rem;
}
.pl-review-details dt {
    color: var(--hub-text-muted);
}
.pl-review-details dd {
    margin: 0;
}
@media (max-width: 640px) {
    .pl-review-details {
        grid-template-columns: 1fr;
        gap: 0.25rem;
    }
    .pl-review-details dd {
        margin-bottom: 0.6rem;
    }
}

/* "3 of 5 ready" beside the Readiness heading. */
.pl-readiness-count {
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--hub-text-muted);
    white-space: nowrap;
}
.pl-readiness-count--ready {
    color: var(--pl-lifecycle-live);
}

/* Facet chips scroll inside their own region on phones (never the page). */
.pl-facets {
    display: flex;
    gap: 0.375rem;
    flex-wrap: wrap;
    align-items: center;
    margin-bottom: 0.75rem;
}
@media (max-width: 640px) {
    .pl-facets {
        flex-wrap: nowrap;
        overflow-x: auto;
        padding-bottom: 0.25rem;
        -webkit-overflow-scrolling: touch;
    }
    .pl-facets .hub-btn {
        flex: 0 0 auto;
    }
}
.pl-facets__count {
    opacity: 0.6;
    font-weight: 400;
}

/* The roster's Show cancelled toggle, above the Registrations table. Colour comes
   from the hub-btn variants, so it follows both themes with nothing to override. */
.pl-roster-filter {
    display: flex;
    justify-content: flex-end;
    margin-bottom: 0.5rem;
}

/* Registrant self-serve page after a class cancel. */
.pl-class-cancelled {
    padding: 0.9rem 1rem;
    margin-bottom: 1rem;
    border: 1px solid var(--pl-lifecycle-cancelled);
    background: var(--color-error-bg);
    border-radius: 8px;
    color: var(--hub-text);
}

/* Leadless guild note on the admin queue. */
.pl-queue-note {
    font-size: 0.8rem;
    color: var(--hub-text-muted);
}

/* Home page Teaching card (class-lifecycle spec PR 2): single-line rows that wrap on phones. */
.pl-teaching {
    list-style: none;
    margin: 0 0 0.75rem;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
.pl-teaching__row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
    padding: 0.4rem 0;
    border-bottom: 1px solid var(--hub-border);
}
.pl-teaching__body {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 0;
}
.pl-teaching__title {
    font-weight: 600;
    color: var(--hub-text);
}
.pl-teaching__note {
    font-size: 0.85rem;
}

/* ── Member wiki (spec A) ───────────────────────────────────────────────────────────
   Prefix: pl-wp- (wiki page). pl-wiki-* and pl-help-* are the Help Center's and are NOT
   reused. Spec B namespaces pl-wp-tab__*, spec D namespaces pl-wp-mod__*, spec E keeps
   pl-gov-*, so three parallel PRs cannot collide on .pl-wp-row or .pl-wp-empty.

   Amber here is literal hex in both themes, copied from the shipped .pl-confirm-warn pair:
   --hub-warn is not a token anywhere in static/css/ and a background:var(--hub-warn) renders
   transparent. Everything else is a --hub-* token. */

.pl-wp-breadcrumbs {
    margin-bottom: 0.75rem;
    font-size: 0.85rem;
    color: var(--hub-text-muted);
}
.pl-wp-breadcrumbs a { color: var(--hub-text-muted); }
.pl-wp-breadcrumbs a:hover { color: var(--hub-text); }

.pl-wp-searchbar { padding: 1rem 1.25rem; margin-bottom: 1rem; }
.pl-wp-searchbar form { max-width: none; }

/* Filter chips are LINKS, so their active state has to be a class — .pl-chip gets its
   selected look from :has(input:checked) and there is no checkbox here. Same pill geometry
   and the same active colors, so the two read as one family side by side. */
.pl-wp-chiprow { margin-bottom: 0.75rem; gap: 0.5rem; }
.pl-wp-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    flex: 0 0 auto;
    min-height: 48px;
    padding: 0.35rem 0.85rem;
    border: 1px solid var(--hub-border);
    border-radius: 999px;
    background: var(--hub-elevated);
    color: var(--hub-text-muted);
    font-size: 0.9rem;
    white-space: nowrap;
}
.pl-wp-chip:hover { color: var(--hub-text); }
.pl-wp-chip--active {
    border-color: var(--hub-blue);
    background: var(--hub-blue-soft);
    color: var(--hub-text);
    font-weight: 600;
}
/* A 44px tap target around a glyph a few pixels wide. The negative margins pull the target
   back over the chip's own padding rather than adding to its height; the chip does get
   wider, which is the trade a reachable clear control is worth on a phone. */
.pl-wp-chip__clear {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
    margin: -0.35rem -0.6rem -0.35rem 0.2rem;
    color: inherit;
    font-size: 0.9rem;
}

/* components/table_search.html used to inline `max-width:340px` on its form, which no
   selector could beat — .pl-wp-searchbar form { max-width: none } at the top of this
   section was dead CSS and
   the wiki's main search box stayed 340px wide inside a 1140px card. The default now
   lives here so a surface can override it. */
.pl-table-search { max-width: 340px; }

/* A "Checked today" line is not a menu item: it is not focusable, and the roving-focus
   handler in components/row_actions.html calls .focus() on every [role="menuitem"], so a
   non-focusable one stops arrow-key navigation dead. Rendered as a plain note instead. */
.pl-row-menu__note { padding: 0.625rem 1rem; margin: 0; font-size: 0.875rem; }

.pl-wp-home__card { padding: 1.25rem; margin-bottom: 1.25rem; }
.pl-wp-home__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 0.75rem;
}
.pl-wp-home__seeall { font-size: 0.85rem; }
.pl-wp-home__headlinks { display: flex; align-items: center; gap: 1rem; }
.pl-wp-home__empty { margin: 0 0 1rem; }
.pl-wp-section__title { margin-top: 0; margin-bottom: 0.5rem; }
.pl-wp-machinegrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); gap: 0.75rem; }
.pl-wp-starterlist { list-style: none; margin: 0 0 0.75rem; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; }

/* The one card. Home rows, search results, spec B's tab rows and spec E's policies all use
   it, which is why the action slot sits outside the title link. */
.pl-wp-card {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 0.75rem;
    min-height: 48px;
    padding: 0.75rem 0;
    border-bottom: 1px solid var(--hub-border);
}
.pl-wp-card:last-child { border-bottom: none; }
.pl-wp-card__main { min-width: 0; flex: 1; }
.pl-wp-card__head { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.pl-wp-card__title { font-weight: 600; color: var(--hub-text); }
.pl-wp-card__title:hover { color: var(--hub-link); }
.pl-wp-card__attrs,
.pl-wp-card__snippet,
.pl-wp-card__meta { margin: 0.2rem 0 0; font-size: 0.85rem; }
.pl-wp-card__snippet {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.pl-wp-card__snippet mark { background: rgba(238, 180, 75, 0.28); color: inherit; border-radius: 3px; }
.pl-wp-card__source {
    display: inline-block;
    margin-right: 0.4rem;
    padding: 0.05rem 0.4rem;
    border: 1px solid var(--hub-border);
    border-radius: 4px;
    font-size: 0.75rem;
}
.pl-wp-card__actions { flex: 0 0 auto; }

.pl-wp-searchcount { margin: 0 0 0.75rem; font-size: 0.9rem; }
.pl-wp-group { padding: 0.5rem 1.25rem; margin-bottom: 1.25rem; }
.pl-wp-search__empty { padding: 1.5rem; }

.pl-wp-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1rem;
}
.pl-wp-header__titles { min-width: 0; }
.pl-wp-status { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.35rem; }
.pl-wp-statusnote,
.pl-wp-attrs,
.pl-wp-accessline { margin: 0.25rem 0 0; font-size: 0.85rem; }
.pl-wp-actions { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
/* Archive is the one action that takes a page away from every member at once, and it lands
   mid-row because .pl-wp-mod__actions is a flex item with Report and Print after it. Its
   own escalation order is right; what it lacked was separation from the routine buttons
   either side, which is what made a destructive control read as the next button along.
   Scoped to the moderation cluster on purpose: .pl-wp-actions also holds Withdraw, which is
   --danger red but only withdraws your own report and wants no such distance. */
.pl-wp-actions .pl-wp-mod__actions .pl-btn--danger { margin-inline: 0.75rem; }
.pl-wp-checked { font-size: 0.85rem; }

/* Neutral, not amber: nothing is wrong, we are only asking. */
.pl-wp-confirmcue {
    margin-bottom: 1rem;
    padding: 0.85rem 1rem;
    border: 1px solid var(--hub-border);
    border-left: 3px solid var(--hub-blue);
    border-radius: 8px;
    background: var(--hub-surface);
}
.pl-wp-confirmcue__ask { margin: 0 0 0.6rem; }
.pl-wp-confirmcue__actions { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; }
.pl-wp-confirmcue__edit { font-size: 0.85rem; }

/* No .pl-wp-archived rules here on purpose: the archived tombstone renders through
   .pl-wp-mod__banner--archived (_wiki_archived_banner.html), and a second amber banner
   style that no template asks for only misleads the next reader about which one is live. */

.pl-wp-factsblock { padding: 1.25rem; margin-bottom: 1.25rem; }
.pl-wp-factsblock__empty { margin: 0; }
.pl-wp-facts { display: grid; grid-template-columns: minmax(8rem, 14rem) 1fr; gap: 0.4rem 1rem; margin: 0; }
.pl-wp-facts__label { margin: 0; font-weight: 600; color: var(--hub-text-muted); }
.pl-wp-facts__value { margin: 0; color: var(--hub-text); }
/* A seeded prompt nobody has answered yet. Quiet, so the answered rows still lead. */
.pl-wp-facts__blank { color: var(--hub-text-muted); font-style: italic; }

/* The locked Official block: its own tinted container, above member content, no edit
   affordance for anyone because there is nothing here to edit. */
.pl-wp-official {
    margin-bottom: 1.25rem;
    padding: 1.25rem;
    border: 1px solid var(--hub-border);
    border-left: 3px solid var(--hub-blue);
    border-radius: 8px;
    background: color-mix(in srgb, var(--hub-blue) 8%, var(--hub-card-bg));
}
.pl-wp-official__head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.pl-wp-official__source { margin: 0.75rem 0 0; font-size: 0.8rem; }

/* TOC is a horizontal chip row pinned under the header, never a sidebar and never an
   accordion — 44px tall, scrolls inside its own container, one behavior at both widths. */
.pl-wp-toc {
    position: sticky;
    /* .hub-content is not a scroll container, so this sticks to the viewport top — the
       same top the opaque .pl-topbar (z-50, 56px) already owns. At top:0/z-5 the chip row
       parked *under* the topbar the moment anyone scrolled, invisible for exactly the
       scroll the control exists for. Offset by the topbar, and sit above page content but
       still below the topbar itself. */
    top: calc(var(--topbar-height) + env(safe-area-inset-top, 0px));
    z-index: 20;
    display: flex;
    gap: 0.5rem;
    min-height: 44px;
    align-items: center;
    margin-bottom: 1rem;
    padding: 0.25rem 0;
    overflow-x: auto;
    background: var(--hub-bg);
    -ms-overflow-style: none;
    scrollbar-width: none;
}
.pl-wp-toc::-webkit-scrollbar { display: none; }
.pl-wp-toc__chip {
    flex: 0 0 auto;
    padding: 0.3rem 0.75rem;
    border: 1px solid var(--hub-border);
    border-radius: 999px;
    background: var(--hub-elevated);
    color: var(--hub-text-muted);
    font-size: 0.85rem;
    white-space: nowrap;
}
.pl-wp-toc__chip--active { border-color: var(--hub-blue); color: var(--hub-text); }

/* Reading rules from the brief: 17px, 1.6, and a wide table scrolls inside its own
   container so the page itself never scrolls horizontally. */
.pl-wp-body { font-size: 17px; line-height: 1.6; margin-bottom: 1.25rem; }
.pl-wp-body img { max-width: 100%; height: auto; border-radius: 8px; }
.pl-wp-body table { display: block; overflow-x: auto; max-width: 100%; }
/* Clear the topbar AND the sticky TOC below it, or a chip tap lands the heading
   underneath the very row that was tapped. */
.pl-wp-body [id] { scroll-margin-top: calc(var(--topbar-height) + 3.5rem); }
.pl-wp-body__empty { padding: 1.5rem; margin-bottom: 1.25rem; }

.pl-wp-attachments { padding: 1.25rem; margin-bottom: 1.25rem; }
.pl-wp-attachments__head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: 0.75rem; }
/* The title's own margin-bottom centres with it and lifts the text off the baseline of
   whatever sits opposite. The head already owns the spacing. */
.pl-wp-official__head .pl-wp-section__title,
.pl-wp-attachments__head .pl-wp-section__title { margin-bottom: 0; }
.pl-wp-attachments__empty { margin: 0; }
.pl-wp-photos { display: grid; grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr)); gap: 0.75rem; margin-bottom: 1rem; }
.pl-wp-photos__item { margin: 0; }
.pl-wp-photos__item img { width: 100%; height: auto; border-radius: 8px; display: block; }
.pl-wp-photos__item figcaption { margin-top: 0.3rem; font-size: 0.8rem; }
.pl-wp-attach__card { padding: 0.6rem 0; border-bottom: 1px solid var(--hub-border); }
.pl-wp-attach__card:last-child { border-bottom: none; }
.pl-wp-attach__name { font-weight: 600; }
.pl-wp-attach__meta { margin: 0.2rem 0 0; font-size: 0.8rem; }

.pl-wp-related { padding: 0.5rem 1.25rem; margin-bottom: 1.25rem; }
/* The byline is rendered twice — a plain footer line at desktop width and the same line
   inside a closed disclosure on a phone. One <details> toggled by CSS is not possible: a
   media query cannot open or close it, and a phone member has eight seconds of attention. */
.pl-wp-bylinewide { margin-bottom: 1.25rem; }
.pl-wp-details { display: none; margin-bottom: 1.25rem; }
.pl-wp-details summary { cursor: pointer; color: var(--hub-text-muted); font-size: 0.9rem; }
.pl-wp-byline { margin: 0.5rem 0 0; font-size: 0.85rem; }
/* Share This Page follows the byline's width swap: its own card on desktop (the only place
   anybody prints a sticker) and the last block inside the phone Details disclosure. */
.pl-wp-qrshare { margin-bottom: 1.25rem; }

/* Only ever printed: a sheet taped to a machine has to say where it came from and how old
   it is, and on screen that is noise. */
.pl-wp-printhead { display: none; }

/* The phone action bar. display is set in a class and never inline, because Alpine's x-show
   strips an inline display when it reveals an element. */
.pl-wp-actionbar { display: none; }
@media (max-width: 768px) {
    .pl-wp-actionbar {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 40;
        display: flex;
        align-items: center;
        gap: 0.5rem;
        padding: 0.6rem 0.75rem;
        border-top: 1px solid var(--hub-border);
        background: var(--hub-card-bg);
    }
    .pl-wp-actionbar .pl-btn { flex: 1; min-height: 48px; }
    /* Spec D's Report cell is a wrapper div, so it gets none of the rule above. Without
       these two it sizes to its content and shoves the bar past its 5.5rem reserve. */
    .pl-wp-actionbar .pl-wp-mod__report { flex: 1; min-width: 0; flex-wrap: nowrap; }
    .pl-wp-actionbar .pl-wp-mod__report .pl-btn { width: 100%; }
    /* Without this the fixed bar covers the last lines of the byline, and a fixed element
       gives no warning that it is doing so. */
    .pl-wp-has-actionbar { padding-bottom: 5.5rem; }
    .pl-wp-bylinewide { display: none; }
    .pl-wp-details { display: block; }
    .pl-wp-qrshare { display: none; }
    /* Two 0.85rem links a thumb-width apart in the section header. Give them a real tap
       height on the width where a thumb is what taps them. */
    .pl-wp-home__seeall { display: inline-flex; align-items: center; min-height: 44px; }
    .pl-wp-facts { grid-template-columns: 1fr; gap: 0.1rem 0; }
    .pl-wp-facts__value { margin-bottom: 0.6rem; font-size: 17px; }
    .pl-wp-header { flex-direction: column; }
    .pl-wp-actions { width: 100%; }
    .pl-wp-actions .pl-btn, .pl-wp-actions .hub-btn { min-height: 48px; }
}

/* The editor. */
.pl-wp-editor__card { padding: 1.25rem; margin-bottom: 1.25rem; }
.pl-wp-editor__head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.pl-wp-editor__hint { margin: 0.5rem 0 0; font-size: 0.85rem; }
.pl-wp-editor__save { display: flex; align-items: center; gap: 0.75rem; margin-top: 1.5rem; }
.pl-wp-savepill { font-size: 0.8rem; color: var(--hub-text-muted); }
.pl-wp-savepill--error { color: #f0a0a0; }
[data-theme="light"] .pl-wp-savepill--error { color: #b03030; }

.pl-wp-resume {
    margin-bottom: 1.25rem;
    padding: 0.85rem 1rem;
    border: 1px solid var(--hub-border);
    border-radius: 8px;
    background: var(--hub-surface);
}
.pl-wp-resume__line { margin: 0 0 0.6rem; }
.pl-wp-resume__actions { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; }

.pl-wp-rows { display: flex; flex-direction: column; gap: 1rem; }
.pl-wp-row { padding: 1rem; background: rgba(255, 255, 255, 0.02); }
.pl-wp-row--dragging { opacity: 0.5; }
.pl-wp-row__grip { cursor: grab; color: var(--hub-text-muted); font-size: 1.1rem; }
/* align-items:center, not flex-start: the Delete button carried an inline margin-top to
   push it clear of a field above, which in a flex row simply dropped it 12px below the
   arrows beside it. The clearance belongs to the container. Both button families are named
   because the wiki's arrows are .pl-btn and other rows still use .hub-btn. */
.pl-wp-row__controls { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.75rem; }
.pl-wp-row__controls .hub-btn,
.pl-wp-row__controls .pl-btn { min-width: 44px; min-height: 44px; }
/* Gloves cannot drag. On touch the arrows are the only reorder control there is. */
@media (hover: none) { .pl-wp-row__grip { display: none; } }
.pl-wp-modalactions { display: flex; align-items: center; gap: 0.75rem; margin-top: 1.5rem; }
.pl-wp-modalnote { margin: 0.75rem 0 0; font-size: 0.85rem; }

.pl-wp-starter-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); gap: 1rem; }
.pl-wp-starter {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    min-height: 48px;
    padding: 1.25rem;
}
.pl-wp-starter__title { font-weight: 600; color: var(--hub-text); }
.pl-wp-starter__desc { font-size: 0.85rem; }
.pl-wp-starter__hint { margin-top: 1rem; font-size: 0.9rem; }
.pl-wp-starter__back { margin-top: 0.5rem; }

.pl-wp-draft { padding: 1.25rem; margin-bottom: 1.25rem; }
.pl-wp-draft__meta { margin: 0.2rem 0 0; font-size: 0.85rem; }
.pl-wp-draft__actions { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; margin-top: 1rem; }

/* .hub-pill--ok's dark-theme green is too pale on a light card. Scoped here rather than
   changing the shared modifier, which would move four existing surfaces — the same
   workaround .pl-invite-list, .pl-automation-card and the two map surfaces already use. */
[data-theme="light"] .pl-wp-card .hub-pill--ok,
[data-theme="light"] .pl-wp-status .hub-pill--ok { color: #1f7a52; }
[data-theme="light"] .pl-wp-card .hub-pill--warn,
[data-theme="light"] .pl-wp-status .hub-pill--warn { color: #9a6a00; }
[data-theme="light"] .pl-wp-card .hub-pill--neutral,
[data-theme="light"] .pl-wp-status .hub-pill--neutral { color: #5b6675; }
[data-theme="light"] .pl-wp-row { background: rgba(0, 0, 0, 0.02); }

@media print {
    .pl-wp-actionbar,
    .pl-wp-toc,
    .pl-wp-related,
    .pl-wp-confirmcue,
    .pl-wp-breadcrumbs,
    .pl-wp-qrshare,
    .pl-wp-actions,
    .pl-wp-page .pl-btn,
    .pl-wp-page .hub-btn {
        display: none !important;
    }
    .pl-wp-printhead { display: block !important; font-size: 0.75rem; }
    /* A sheet taped to a machine carries the byline, so the wide line prints and the phone
       disclosure (which a print job cannot open) stays out of the way. */
    .pl-wp-bylinewide { display: block !important; }
    .pl-wp-details { display: none !important; }
    .pl-wp-page, .pl-wp-page .hub-card { background: #fff !important; color: #000 !important; border-color: #ccc !important; }
    .pl-wp-page .hub-text-muted { color: #333 !important; }
    .pl-wp-has-actionbar { padding-bottom: 0 !important; }
}

/* ── Member wiki: moderation (spec D) ───────────────────────────────────────────────
   Prefix: pl-wp-mod__ (spec A owns bare pl-wp-*, spec B owns pl-wp-tab__*), so three
   parallel PRs cannot silently collide on .pl-wp-empty or .pl-wp-row.

   Amber is literal hex in both themes, copied from the shipped .pl-confirm-warn pair:
   --hub-warn is not a token anywhere in static/css/ and background:var(--hub-warn) renders
   transparent. Everything else here is a --hub-* token. */
.pl-wp-mod__banner {
    padding: 1rem 1.25rem;
    margin-bottom: 1.25rem;
    border-left: 4px solid var(--hub-border);
    background: var(--hub-surface);
    border-radius: 6px;
}
/* The rule carries the colour and the text carries the meaning: gold TEXT on --hub-surface
   fails contrast on the light theme, so the heading stays --hub-text at 600. */
.pl-wp-mod__banner--review { border-left-color: var(--color-tuscan-yellow); }
.pl-wp-mod__banner--archived { border-left-color: var(--hub-border-strong); }
.pl-wp-mod__banner--lock { border-left-color: var(--hub-blue); }
.pl-wp-mod__banner-title { margin: 0 0 0.5rem; font-weight: 600; color: var(--hub-text); }
.pl-wp-mod__banner-line { margin: 0 0 0.5rem; color: var(--hub-text); line-height: 1.6; }
.pl-wp-mod__banner-by { margin: 0.5rem 0 0; font-size: 0.85rem; }
.pl-wp-mod__banner-actions {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-top: 1rem;
}

.pl-wp-mod__quote {
    margin: 0;
    padding-left: 0.75rem;
    border-left: 2px solid var(--hub-border);
    font-style: italic;
    color: var(--hub-text);
    line-height: 1.6;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.pl-wp-mod__quote--short { -webkit-line-clamp: 2; line-clamp: 2; }
/* x-show only toggles display:none, so the expanded state is a class and never an inline
   display (Rule 12). */
.pl-wp-mod__quote--open { -webkit-line-clamp: unset; line-clamp: unset; overflow: visible; }
.pl-wp-mod__quotewrap { display: flex; flex-direction: column; align-items: flex-start; }
.pl-wp-mod__more {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0;
    background: none;
    border: 0;
    color: var(--hub-blue);
    font-size: 0.85rem;
    cursor: pointer;
}

.pl-wp-mod__note {
    background: var(--hub-surface);
    border-left: 4px solid var(--hub-blue);
    border-radius: 6px;
    padding: 1rem 1.25rem;
    margin-bottom: 1.25rem;
}
.pl-wp-mod__note-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: 0.5rem;
}
.pl-wp-mod__note-body { color: var(--hub-text); line-height: 1.6; }
.pl-wp-mod__note-by { margin: 0.75rem 0 0; font-size: 0.85rem; }
.pl-wp-mod__note-remove { margin-bottom: 1rem; }
.pl-wp-mod__divider { border: 0; border-top: 1px solid var(--hub-border); margin: 0 0 1.25rem; }

/* Quiet neutral attribute chip — no fill, because colour is reserved for status. */
.pl-wp-mod__chip {
    display: inline-block;
    padding: 0.1rem 0.5rem;
    border: 1px solid var(--hub-border);
    border-radius: 999px;
    font-size: 0.75rem;
    color: var(--hub-text-muted);
}

/* No margin-bottom: this renders as a flex ITEM inside A's .pl-wp-actions, which centres
   on align-items:center, so a bottom margin lifts these three controls ~12px above Edit /
   Still accurate / Report / Print in the same row and grows the row by 24px. Rule 18's
   clearance is A's row's job; nothing follows this inside it. */
.pl-wp-mod__actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.pl-wp-mod__report { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.pl-wp-mod__reported { font-size: 0.85rem; }
/* .pl-btn is already nowrap, so the risk is spilling past the border, not wrapping. At
   360px the four-item bar overflows and this is where it lands. min-width:0 lets it
   shrink below its content and overflow:hidden clips what is left rather than painting
   text over the button's edge. No text-overflow: it does nothing on an inline-flex
   element, and a declaration that does nothing is the bug this round already fixed twice. */
.pl-wp-mod__report-btn { min-width: 0; overflow: hidden; }
/* The chip is the page's ONE coloured pill; hub-pill--primary paints it, this only keeps
   it from being stretched by the flex header it sits in. */
.pl-wp-mod__note-chip { flex: 0 0 auto; }
.pl-wp-mod__modal-actions {
    display: flex;
    gap: 0.75rem;
    justify-content: flex-end;
    /* Rule 18: the submit never touches whatever sits under it. */
    margin-top: 1.5rem;
}

.pl-wp-mod__review-card {
    margin-bottom: 1rem;
    border-bottom: 1px solid var(--hub-border);
}
.pl-wp-mod__review-card:last-child { border-bottom: 0; margin-bottom: 0; }
.pl-wp-mod__review-head {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-bottom: 0.5rem;
}
.pl-wp-mod__tabs { margin-bottom: 1.5rem; }
.pl-wp-mod__homelink { margin: 0 0 1rem; }
.pl-wp-mod__explainer { margin: -0.75rem 0 1.5rem; }

/* Written empty state. Never a blank region. */
.pl-wp-mod__empty {
    padding: 2.5rem 1rem;
    text-align: center;
    color: var(--hub-text-muted);
    max-width: 44ch;
    margin: 0 auto;
}
/* Give the headline a step of contrast; without it both lines are the same muted grey at
   the same size and the state reads as one undifferentiated paragraph. */
.pl-wp-mod__empty p:first-child {
    color: var(--hub-text);
    font-size: 1.05rem;
    font-weight: 600;
    margin: 0 0 0.5rem;
}

.pl-wp-mod__conflict-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1.25rem; }
.pl-wp-mod__conflict-body { max-height: 420px; overflow-y: auto; }
.pl-wp-mod__conflict-actions {
    display: flex;
    gap: 0.75rem;
    flex-wrap: wrap;
    margin: 1.5rem 0 0.75rem;
}
.pl-wp-mod__conflict-note { margin: 0 0 1.5rem; }

.pl-wp-mod__history-card {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.75rem 0;
    border-bottom: 1px solid var(--hub-border);
}
.pl-wp-mod__history-card:last-child { border-bottom: 0; }
/* min-width:0 so a long note can ellipsize instead of shoving the Revert button off. */
.pl-wp-mod__history-main { flex: 1; min-width: 0; }
.pl-wp-mod__history-when { color: var(--hub-text); font-weight: 600; }
.pl-wp-mod__history-who { margin: 0.25rem 0 0; font-size: 0.85rem; }
.pl-wp-mod__redirect { margin-top: 1rem; }

@media (max-width: 900px) {
    .pl-wp-mod__conflict-grid { grid-template-columns: 1fr; }
}

/* 390px, one thumb, gloves. Every control is a 48px tap target and nothing stacks
   sideways; no hover affordance exists anywhere on these screens. */
@media (max-width: 640px) {
    .pl-wp-mod__conflict-body { max-height: 40vh; }
    .pl-wp-mod__history-card { flex-direction: column; align-items: stretch; }
    .pl-wp-mod__history-action .pl-btn { width: 100%; min-height: 48px; }
    .pl-wp-mod__history-when { display: inline-flex; align-items: center; min-height: 48px; }
    .pl-wp-mod__banner-actions { flex-direction: column; }
    .pl-wp-mod__banner-actions .pl-btn { width: 100%; min-height: 48px; }
    .pl-wp-mod__conflict-actions { flex-direction: column; }
    .pl-wp-mod__conflict-actions .pl-btn { width: 100%; min-height: 48px; }
    .pl-wp-mod__modal-actions { flex-direction: column-reverse; }
    .pl-wp-mod__modal-actions .pl-btn { width: 100%; min-height: 48px; }
    .pl-wp-mod__report .pl-btn { min-height: 48px; }
    .pl-wp-mod__more { min-height: 48px; }
    .pl-wp-mod__tabs .vote-tab { min-height: 48px; display: inline-flex; align-items: center; }
}

/* The desktop header row is desktop-only: on a phone these actions live inside spec A's
   single overflow menu, because two kebabs both containing Edit reads as a bug. */
@media (max-width: 768px) {
    .pl-wp-mod__actions { display: none; }
}

/* ── Member wiki: the guild Wiki tab (spec B) ───────────────────────────────
   Namespace: pl-wp-tab__* and nothing else. Spec A owns bare pl-wp-*, spec D owns
   pl-wp-mod__*, spec E keeps pl-gov-*, so three parallel PRs cannot collide on a
   .pl-wp-row or a .pl-wp-empty. Every colour is a theme token; the only literal hexes
   are the light-theme pill overrides, which copy the four the repo already carries.  */

.pl-wp-tab__search {
    display: flex;
    align-items: flex-end;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1rem;
}
.pl-wp-tab__search form { flex: 1; min-width: 16rem; max-width: none; }
.pl-wp-tab__scope { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.5rem; }
.pl-wp-tab__scope-chip {
    display: inline-flex;
    align-items: center;
    min-height: 2rem;
    padding: 0.25rem 0.75rem;
    border: 1px solid var(--hub-border);
    border-radius: 999px;
    background: transparent;
    color: var(--hub-text-muted);
    font-size: 0.85rem;
    cursor: pointer;
}
.pl-wp-tab__scope-chip--active {
    border-color: var(--color-tuscan-yellow);
    color: var(--hub-text);
    cursor: default;
}

/* Two columns on desktop, one below 900px. The display lives here and never in an inline
   style on the x-show pane: Alpine strips inline display when it reveals an element
   (Rule 12 — the bug that collapsed the orientation slot table). */
.pl-wp-tab__grid {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    gap: 1.5rem;
    align-items: start;
}
/* Nothing to put in the right-hand column: the list takes the whole width rather than
   leaving a third of the page empty beside it. */
.pl-wp-tab__grid--solo { grid-template-columns: minmax(0, 1fr); }
.pl-wp-tab__col { min-width: 0; display: flex; flex-direction: column; gap: 1rem; }
/* A lead's entry point to the wanted list when there is no card to hang it on. The
   column's own gap does the spacing, so this carries no margin of its own. */
.pl-wp-tab__panel-link { margin: 0; font-size: 0.85rem; }

.pl-wp-tab__group { padding: 1rem 1.25rem; }
.pl-wp-tab__group-title { margin-top: 0; margin-bottom: 0.5rem; }
.pl-wp-tab__group-more,
.pl-wp-tab__panel-more { display: inline-block; margin-top: 0.75rem; font-size: 0.85rem; }
.pl-wp-tab__row { border-bottom: 1px solid var(--hub-border); }
.pl-wp-tab__row:last-of-type { border-bottom: none; }
.pl-wp-tab__row-title { margin: 0; font-weight: 600; }
.pl-wp-tab__row-meta { margin: 0.2rem 0 0; font-size: 0.85rem; }
.pl-wp-tab__row-actions {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
    margin-top: 0.5rem;
}
.pl-wp-tab__row-edit { font-size: 0.85rem; }

.pl-wp-tab__recent,
.pl-wp-tab__panel,
.pl-wp-tab__misses,
.pl-wp-tab__wanted { padding: 1rem 1.25rem; background: var(--hub-surface); }
.pl-wp-tab__panel-title { margin-top: 0; margin-bottom: 0.35rem; }
.pl-wp-tab__panel-empty { margin: 0.5rem 0 0; }
.pl-wp-tab__panel-done { margin: 0.5rem 0; color: var(--hub-text-muted); }
.pl-wp-tab__panel-row { padding: 0.75rem 0; border-bottom: 1px solid var(--hub-border); }
.pl-wp-tab__panel-row:last-of-type { border-bottom: none; }
.pl-wp-tab__recent-row { margin: 0.4rem 0; display: flex; gap: 0.5rem; flex-wrap: wrap; font-size: 0.9rem; }

.pl-wp-tab__miss { padding: 0.75rem 0; border-bottom: 1px solid var(--hub-border); }
.pl-wp-tab__miss:last-of-type { border-bottom: none; }
.pl-wp-tab__miss-query { margin: 0; font-weight: 600; }
.pl-wp-tab__miss-people { margin: 0.2rem 0 0; font-size: 0.85rem; }
.pl-wp-tab__miss-actions { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; margin-top: 0.5rem; }
.pl-wp-tab__miss-onlist { font-size: 0.85rem; }

.pl-wp-tab__wanted-row { padding: 0.75rem 0; border-bottom: 1px solid var(--hub-border); }
.pl-wp-tab__wanted-row:last-of-type { border-bottom: none; }
.pl-wp-tab__wanted-title { margin: 0; font-weight: 600; }
.pl-wp-tab__wanted-meta,
.pl-wp-tab__wanted-note,
.pl-wp-tab__wanted-claim { margin: 0.2rem 0 0; font-size: 0.85rem; }
.pl-wp-tab__wanted-count { font-weight: 600; color: var(--hub-text); }
.pl-wp-tab__wanted-done { margin: 0.4rem 0 0; font-size: 0.9rem; }
.pl-wp-tab__wanted-actions { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; margin-top: 0.5rem; }
.pl-wp-tab__wanted-done-list { margin-top: 0.75rem; }
.pl-wp-tab__wanted-scope { padding: 1rem 1.25rem; margin-bottom: 1.25rem; }
/* .hub-form-group carries margin-bottom:1.25rem, margins do not collapse in a flex
   container, and align-items:flex-end lines up margin boxes — so the button sat 20px
   below the select it submits. */
.pl-wp-tab__switcher { display: flex; align-items: flex-end; gap: 0.75rem; flex-wrap: wrap; }
.pl-wp-tab__switcher .hub-form-group { margin-bottom: 0; }
.pl-wp-tab__editor { padding: 1.5rem; margin-top: 1.25rem; }
.pl-wp-tab__editor-rows { display: flex; flex-direction: column; gap: 1rem; }
.pl-wp-tab__editor-row { padding: 1rem; background: var(--hub-surface); }

.pl-wp-tab__verify { margin-top: 0.35rem; }
.pl-wp-tab__verify:empty { margin-top: 0; }
.pl-wp-tab__verify-credit,
.pl-wp-tab__verify-note,
.pl-wp-tab__verify-hint { margin: 0.2rem 0 0; font-size: 0.85rem; }
.pl-wp-tab__verify-note { font-style: italic; }
.pl-wp-tab__verify-actions { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.5rem; }

.pl-wp-tab__empty { padding: 1.5rem; }
.pl-wp-tab__empty p { margin: 0 0 0.5rem; }
.pl-wp-tab__empty-headline { font-size: 1.05rem; font-weight: 600; margin: 0 0 0.5rem; }
.pl-wp-tab__empty-actions,
.pl-wp-tab__empty-scope { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; margin-top: 1rem; }
.pl-wp-tab__empty-write { margin: 1rem 0 0; font-size: 0.9rem; }
.pl-wp-tab__requested { margin: 0; font-size: 0.9rem; }

/* Every in-flight one-tap control dims and stops taking taps, so a phone double tap cannot
   double post; verify()'s 60-second same-member guard is the server-side backstop. Scoped
   to the tab root rather than to each action row, so the compact Verify button also gets it
   where it sits inside spec A's card partial. The wanted rows are named separately because
   they also render on /wiki/wanted/, outside the tab. */
.pl-wp-tab .htmx-request,
.pl-wp-tab__wanted-actions .htmx-request { opacity: 0.55; pointer-events: none; }

/* No light-theme pill override here on purpose. Every status pill this tab renders comes
   through spec A's shared card partial, so it already sits inside .pl-wp-card and picks up
   A's [data-theme="light"] fix for .hub-pill--ok's too-pale dark green. The wanted rows and
   the lead panels render no status pill at all. Adding a rule for them would be dead CSS
   claiming to fix something that does not happen — and the shared .hub-pill--ok modifier
   stays untouched either way, because changing it would move five other surfaces. */

@media (max-width: 900px) {
    .pl-wp-tab__grid { grid-template-columns: minmax(0, 1fr); }
    /* A guild lead with forty minutes on a Sunday is who this feature is for. Stacking the
       panels under as many as 72 page rows (six kinds x 12) asks them to thumb past the
       whole directory to reach their to-do list, so for a lead the columns swap. For a
       member nothing moves, because the panels do not render at all. */
    .pl-wp-tab__grid--lead .pl-wp-tab__col--panels { order: 1; }
    .pl-wp-tab__grid--lead .pl-wp-tab__col--list { order: 2; }
    /* Column at this width: the action belongs UNDER the search box, not beside it.
       `align-items: stretch` on a row made the anchor as tall as the whole search form
       next to it — a solid yellow block the size of a card, which on a guild with no
       pages was the largest thing on the screen. */
    .pl-wp-tab__search { flex-direction: column; align-items: stretch; }
    .pl-wp-tab__search > .pl-btn { align-self: flex-start; }
    /* Gloves, dust, bad light. .pl-btn--sm sets min-height:0 (about 27px), so every
       control on these surfaces is raised by CONTAINER ROOT rather than by action-row
       class. Enumerating the action rows missed the three controls that matter most: the
       compact Verify button lands in spec A's .pl-wp-card__actions slot and never in one
       of B's own rows; the zero-result screen and the wanted editor live outside the tab
       entirely; and the tab's own Search button sat at 27px beside a 48px scope chip.

       The enumeration was still short by a whole surface. .pl-wp-tab covers the guild
       page's Wiki tab and nothing else, so /wiki/p/<slug>/ — the screen a QR sticker on a
       machine opens, and the likeliest phone surface in the building — kept a 27px
       toolbar. Every wiki template now sets body class .pl-wp-screen, which is the real
       container root for the feature.

       Being body-scoped it does also reach the three chrome buttons the hub renders on
       every page (_tour.html's Resume tour, and the welcome modal's two), on wiki screens
       only and at phone widths only. That is deliberate and harmless: those are a tour
       control and a modal footer, which want a 48px target on a phone anyway. */
    .pl-wp-tab .pl-btn,
    .pl-wp-tab .hub-btn,
    .pl-wp-tab__scope-chip,
    .pl-wp-screen .pl-btn,
    .pl-wp-screen .hub-btn { min-height: 48px; }
    /* Bare links standing in an action row are targets too, and were never covered by a
       rule that only knew about buttons. .pl-wp-tab__scope-chip and __row-edit are NOT
       mirrored under .pl-wp-screen: they exist only in _guild_wiki_tab.html, which renders
       on the guild page, so a .pl-wp-screen copy of them could never match anything.
       __miss-onlist is, because _wiki_miss_row.html also renders on /wiki/wanted/. */
    .pl-wp-screen .pl-wp-tab__miss-onlist,
    .pl-wp-tab .pl-wp-tab__row-edit,
    .pl-wp-tab .pl-wp-tab__miss-onlist { display: inline-flex; align-items: center; min-height: 48px; }
}

/* Reviewer reassurance line above the class review decision radios. */
.pl-review-reassure {
    margin: 0 0 1rem;
    font-size: 0.85rem;
    line-height: 1.5;
    color: var(--hub-text-muted);
}

/* ========================================
   One Class Screen (issue #399)
   ========================================
   The per-class management screen — one page per class, one tab strip, whichever of the
   four viewer roles is looking at it. Header, the meta line under the title, the "why you
   are seeing this" note a guild lead gets, and the action row under the page. Every rule
   here is new markup this feature introduces; nothing above it changes. */
.pl-class-header { display:flex; justify-content:space-between; align-items:flex-start; gap:1rem; flex-wrap:wrap; margin-bottom:0.75rem; }
.pl-class-header__main { min-width: 0; }
.pl-class-header__title { margin: 0 0 0.35rem; }
.pl-class-header__badges { display:flex; gap:0.4rem; flex-wrap:wrap; align-items:center; }
.pl-class-header__actions { display:flex; gap:0.5rem; flex-wrap:wrap; }
.pl-class-header--center { align-items: center; }
/* The one-line "what this page is for" beside a portal <h1>, where a page_header block used
   to sit one line underneath it and make two headings for one page. */
.pl-class-header__lead { margin: 0.25rem 0 0; max-width: 65ch; color: var(--hub-text-muted); font-size: 0.9rem; }
.pl-class-header--tight { margin-bottom: 0.5rem; }

.pl-class-meta { display:flex; flex-wrap:wrap; gap:0.25rem 0.9rem; margin:0.5rem 0 0; color:var(--hub-text-muted); font-size:0.85rem; }
.pl-class-meta__item { white-space: nowrap; }
.pl-class-meta__item:not(:last-child)::after { content:" ·"; opacity:0.55; }

.pl-class-context { display:flex; gap:0.6rem; align-items:flex-start; background:var(--hub-surface); border-left:3px solid var(--hub-blue); border-radius:6px; padding:0.7rem 0.9rem; margin:0 0 1.25rem; color:var(--hub-text-muted); font-size:0.875rem; line-height:1.5; }
.pl-class-context__icon { flex:0 0 auto; color:var(--hub-blue); margin-top:1px; }
.pl-class-context strong { color:var(--hub-text); font-weight:600; }

.pl-class-actions { display:flex; gap:0.375rem; flex-wrap:wrap; align-items:center; margin-top:1.5rem; }
.pl-class-actions__break { flex-basis:100%; height:0; margin:0.4rem 0 0.15rem; border-top:1px solid var(--hub-border); }
@media (max-width: 600px) {
    .pl-class-actions { display:grid; grid-template-columns:1fr 1fr; gap:0.5rem; }
    .pl-class-actions .hub-btn { width:100%; text-align:center; justify-content:center; }
    .pl-class-actions__break { grid-column:1 / -1; margin:0.25rem 0; }
    .pl-class-header__actions { width:100%; }
    .pl-class-header__actions .hub-btn { flex:1 1 auto; text-align:center; }
}

/* One row of a Needs Attention group: what needs doing on the left, the buttons that do
   it on the right, stacking to full-width buttons on a phone. */
.pl-attention-row { display:flex; justify-content:space-between; align-items:center; gap:0.5rem; padding:0.5rem 0; border-bottom:1px solid var(--hub-border); flex-wrap:wrap; }
.pl-attention-row:last-child { border-bottom: none; }
.pl-attention-row__main { display:flex; flex-direction:column; gap:2px; min-width:0; }
.pl-attention-row__sub { color:var(--hub-text-muted); font-size:0.85rem; }
.pl-attention-row__actions { display:flex; gap:6px; flex-wrap:wrap; }
.pl-attention-group__hint { color:var(--hub-text-muted); margin:0 0 0.6rem; font-size:0.9rem; }
@media (max-width: 600px) {
    .pl-attention-row { flex-direction:column; align-items:stretch; }
    .pl-attention-row__actions .hub-btn { flex:1 1 auto; text-align:center; }
}

.pl-guild-attention { margin: 0 0 1.25rem; }

/* Site Settings → Features (#405). Same card language as the Automations tab beside it, but
   three columns rather than five: a feature has a name, a state, and a message — no schedule,
   no last run, nothing to run now. */
.pl-automation-card--feature {
    /* Two rows, not one: the "what off does" line is a sentence, and squeezing it into a
       third of a 760px form turned every card into a six-line wrap. Name and description take
       the full width; the state control and the message input share the row beneath. */
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center;
    row-gap: 0.75rem;
}
.pl-automation-card--feature .pl-automation-main { grid-column: 1 / -1; }
/* Django's RadioSelect renders a wrapping <div> with one <div> per choice (it stopped using
   <ul>/<li> in 4.0), so lay the choices out on that structure, not on a list. */
.pl-feature-states > div { display: flex; gap: 0.75rem; flex-wrap: wrap; }
.pl-feature-states > div > div { margin: 0; }
.pl-feature-states label {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.8125rem;
    color: var(--hub-text);
    cursor: pointer;
    white-space: nowrap;
}
.pl-feature-message input[type="text"] {
    width: 100%;
    padding: 0.4rem 0.55rem;
    font-size: 0.8125rem;
    color: var(--hub-text);
    background: var(--hub-input-bg, var(--hub-card-bg));
    border: 1px solid var(--hub-input-border);
    border-radius: 6px;
}

@media (max-width: 768px) {
    /* The five-column automation grid already stacks here; the feature card must too, or the
       message input is squeezed to nothing on a phone. */
    .pl-automation-card--feature { grid-template-columns: minmax(0, 1fr); }
}
