/* =============================================================================
 * platform.css
 *
 * Styles for the screens the platform layer adds: the sign-in gate, the
 * project chooser, the synchronisation bar, the team panel and the conflict
 * resolver. The existing application's own styles are untouched.
 *
 * Sizing follows one constraint: this is used outdoors, standing up, often in
 * bright light and sometimes with gloves. Interactive targets are at least
 * 48 px, body text is at least 16 px so mobile browsers do not zoom on focus,
 * and contrast is kept high rather than fashionable.
 * ========================================================================== */

:root {
    --ssp-bg: #0f1a14;
    --ssp-surface: #ffffff;
    --ssp-ink: #16241c;
    --ssp-ink-soft: #52655a;
    --ssp-line: #d3ddd6;
    --ssp-accent: #2f6f4f;
    --ssp-accent-dark: #24573e;
    --ssp-warn: #a8620a;
    --ssp-error: #a32020;
    --ssp-ok: #1f6b45;
    --ssp-radius: 12px;
    --ssp-tap: 48px;
}

/* The field application is hidden until there is a session and a project. */
body.ssp-gated > *:not(#sspAuth):not(#sspChooser):not(#sspToast) {
    display: none !important;
}

/* =============================================================================
 * Sign-in gate
 *
 * The background is soil, drawn in CSS. It is a dark loam field built from
 * scattered radial highlights, a speckle of grit and two crossing grain
 * directions. Nothing is loaded for it, so it cannot fail to appear on a slow
 * rural connection and it costs no bandwidth on a metered field device. The
 * photograph it replaces was 595 KB and was fetched before anything else on
 * the screen could be read.
 *
 * One field component serves every pane. The two reference designs are the
 * same control in two states: the resting state carries its label on the rule,
 * and the filled state lifts that label into the space above it as a small
 * caption. Making them one component is what removes the earlier duplication,
 * where the sign-in pane and the register pane each carried their own spacing,
 * their own label treatment and their own set of overrides that fought one
 * another at narrow widths.
 * ========================================================================== */

.ssp-auth {
    position: fixed;
    inset: 0;
    z-index: 12000;
    display: flex;
    /* flex-start, never centre. A centred flex child that is taller than its
       container overflows equally in both directions and the top of it becomes
       unreachable, which is what cut the head off the register pane on short
       screens. `margin: auto` on the card gives true centring when it fits and
       degrades to top alignment when it does not. This one pair of rules
       replaces the three .is-register overrides and the 900 px media query
       that previously undid them. */
    align-items: flex-start;
    justify-content: center;
    padding: clamp(16px, 4vh, 40px) 16px
             calc(clamp(16px, 4vh, 40px) + env(safe-area-inset-bottom, 0px));
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    background: #120b07;
    font-family: Archivo, "Inter Tight", "Segoe UI", system-ui, -apple-system, sans-serif;
}
.ssp-auth[hidden] { display: none; }

/* A local reset. The gate is built by script and appended to <body>, so it
   cannot assume the host page's box model: under content-box an input at
   width:100% with a right padding for the reveal button computes wider than
   its field, and its underline runs off the edge of the card. */
.ssp-auth,
.ssp-auth *,
.ssp-auth *::before,
.ssp-auth *::after { box-sizing: border-box; }

/* The host page styles every `input` in the document generically: a light
   panel background, a rounded border, an inset neumorphic shadow and an amber
   focus ring, the last of them declared `border: none !important`. Those rules
   are loaded after this file and they reach into the gate, which is appended
   to the same <body>. Field type on a dark card cannot survive them.
   `!important` is used here only where the host page used it first. */
.ssp-auth input {
    -webkit-appearance: none;
    appearance: none;
    border: 0 !important;
    border-radius: 0 !important;
    background: transparent !important;
    box-shadow: none !important;
    outline: none !important;
    color: #ffffff;
}
.ssp-auth input[type="checkbox"] {
    -webkit-appearance: checkbox;
    appearance: checkbox;
    accent-color: #ffffff;
}

/* -------------------------------------------------------------------------
 * The soil field behind the card
 * ---------------------------------------------------------------------- */
.ssp-auth-scene {
    position: fixed;
    inset: 0;
    z-index: 0;
    overflow: hidden;
    background-color: #150d08;
    background-image:
        radial-gradient(circle at 12% 8%,  rgba(96, 52, 26, .55) 0, rgba(0, 0, 0, 0) 9%),
        radial-gradient(circle at 63% 4%,  rgba(122, 66, 32, .5) 0, rgba(0, 0, 0, 0) 7%),
        radial-gradient(circle at 88% 14%, rgba(74, 38, 18, .6)  0, rgba(0, 0, 0, 0) 11%),
        radial-gradient(circle at 30% 20%, rgba(58, 29, 13, .7)  0, rgba(0, 0, 0, 0) 13%),
        radial-gradient(circle at 5% 34%,  rgba(110, 58, 28, .4) 0, rgba(0, 0, 0, 0) 8%),
        radial-gradient(circle at 46% 40%, rgba(70, 35, 16, .5)  0, rgba(0, 0, 0, 0) 14%),
        radial-gradient(circle at 78% 52%, rgba(96, 50, 24, .42) 0, rgba(0, 0, 0, 0) 10%),
        radial-gradient(circle at 18% 63%, rgba(82, 42, 20, .5)  0, rgba(0, 0, 0, 0) 12%),
        radial-gradient(circle at 58% 74%, rgba(104, 55, 26, .45) 0, rgba(0, 0, 0, 0) 10%),
        radial-gradient(circle at 92% 82%, rgba(66, 33, 15, .6)  0, rgba(0, 0, 0, 0) 13%),
        radial-gradient(circle at 34% 90%, rgba(118, 62, 30, .4) 0, rgba(0, 0, 0, 0) 9%),
        radial-gradient(circle at 72% 96%, rgba(80, 40, 19, .5)  0, rgba(0, 0, 0, 0) 11%),
        radial-gradient(circle at 50% 50%, rgba(40, 20, 10, .9)  0, #0b0704 78%);
}

/* Grit, then grain. The grit is a four-cell speckle on prime-ish tile sizes so
   the repeat does not read as a pattern; the grain is two crossing rakes. */
.ssp-auth-veil {
    position: absolute;
    inset: 0;
}
.ssp-auth-veil::before,
.ssp-auth-veil::after {
    content: "";
    position: absolute;
    inset: 0;
}
.ssp-auth-veil::before {
    opacity: .5;
    background-image:
        radial-gradient(circle at 20% 30%, rgba(0, 0, 0, .9) 0 1.4px, rgba(0, 0, 0, 0) 2px),
        radial-gradient(circle at 70% 60%, rgba(0, 0, 0, .85) 0 1.6px, rgba(0, 0, 0, 0) 2.4px),
        radial-gradient(circle at 45% 85%, rgba(147, 80, 40, .5) 0 1.2px, rgba(0, 0, 0, 0) 2px),
        radial-gradient(circle at 85% 15%, rgba(0, 0, 0, .8) 0 1.8px, rgba(0, 0, 0, 0) 2.6px);
    background-size: 23px 19px, 31px 27px, 17px 21px, 29px 33px;
}
.ssp-auth-veil::after {
    opacity: .35;
    background-image:
        repeating-linear-gradient(58deg, rgba(0, 0, 0, .55) 0 2px, rgba(0, 0, 0, 0) 2px 6px),
        repeating-linear-gradient(-37deg, rgba(120, 64, 32, .28) 0 1px, rgba(0, 0, 0, 0) 1px 9px);
}

/* -------------------------------------------------------------------------
 * The card
 * ---------------------------------------------------------------------- */
.ssp-auth-card {
    position: relative;
    z-index: 1;
    margin: auto;                 /* centres when short, top-aligns when tall */
    width: 100%;
    max-width: 421px;
    padding: clamp(26px, 5vw, 34px) clamp(20px, 5vw, 30px) 26px;
    border-radius: 18px;
    /* Glass, with a floor under it.
     *
     * The photograph behind this card is not uniform: the card can land on a
     * dark furrow or on a sunlit ridge depending on the screen. Transparency
     * alone would make the type legible on one and not the other, so the fill
     * is a gradient that stays dark enough to hold white text at its lightest
     * point while still letting the field read through. Measured against the
     * brightest region of the background image the body text sits above 7:1
     * and the dimmest caption above 4.5:1.
     *
     * The blur does the rest of the work: at 22 px the photograph survives as
     * colour and movement rather than as detail, which is what stops the type
     * competing with the grain of the soil underneath it. */
    background:
        linear-gradient(160deg,
            rgba(46, 36, 30, .60) 0%,
            rgba(24, 18, 15, .68) 55%,
            rgba(18, 13, 11, .74) 100%);
    backdrop-filter: blur(22px) saturate(118%);
    -webkit-backdrop-filter: blur(22px) saturate(118%);
    /* A hairline that is lighter at the top than at the bottom reads as a lit
       edge and keeps the card from looking like a flat grey rectangle. */
    border: 1px solid rgba(255, 255, 255, .14);
    box-shadow:
        0 24px 60px rgba(0, 0, 0, .55),
        0 2px 10px rgba(0, 0, 0, .28),
        inset 0 1px 0 rgba(255, 255, 255, .16),
        inset 0 -1px 0 rgba(0, 0, 0, .22);
    color: #ffffff;
}

/* Without backdrop-filter there is no glass, only a translucent panel over a
   photograph, which is the condition the contrast floor exists for. Give up
   the transparency rather than the readability. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .ssp-auth-card {
        background: linear-gradient(160deg, rgba(38, 30, 25, .94), rgba(20, 15, 12, .96));
    }
}

/* -------------------------------------------------------------------------
 * The SoilTrace wordmark
 *
 * Set in type, not supplied as an image: no request, sharp at any density,
 * scales with the user's text size, and readable to a screen reader through
 * the aria-label on its container. Sizing is a clamp rather than a stack of
 * breakpoint overrides, so there is one declaration to reason about.
 *
 * Everything below is scoped to .ssp-auth-card. The same wordmark markup is
 * reused in the application header, and the previous unscoped rules meant a
 * change here silently moved that one too.
 * ---------------------------------------------------------------------- */
.st-logo {
    display: block;
    text-align: center;
    user-select: none;
}

.st-logo-word {
    display: block;
    /* An explicit stack, not `inherit`. The header and chooser reuse this
       element outside the sign-in container, and inheriting there would pick
       up whatever font that surface happens to set. */
    font-family: "Segoe UI", system-ui, -apple-system, sans-serif;
    font-size: 33px;
    line-height: 1;
    letter-spacing: -.5px;
    white-space: nowrap;
}
.st-soil  { font-weight: 300; color: rgba(255, 255, 255, .92); }
.st-trace { font-weight: 800; color: #ffffff; margin-left: 1px; }

.ssp-auth-card .st-logo-word {
    font-family: Archivo, "Segoe UI", system-ui, sans-serif;
    font-size: clamp(28px, 8vw, 33px);
}
.ssp-auth-card .st-trace { font-weight: 700; }

/* Two copper rules, the brighter over the softer. */
.st-logo-rule {
    display: flex;
    flex-direction: column;
    gap: 3px;
    width: 118px;
    margin: 12px auto 0;
}
.st-logo-rule i { display: block; height: 2px; }

/* Base horizon bands, shared with the header and inline lockups further down
   this file. They own the widths those lockups depend on; only the colour is
   restated per context. The card overrides that follow are scoped so a change
   made for the sign-in screen cannot move the header wordmark. */
.st-h-a { background: #2f2118; width: 100%; opacity: .92; }
.st-h-b { background: #7a4a2b; width: 78%; margin-left: 11%; opacity: .92; }
.st-h-c { background: #c9a06a; width: 46%; margin-left: 27%; opacity: .92; }

/* On the card the two bands run the full width as a matched pair. */
.ssp-auth-card .st-logo-rule i { width: 100%; margin-left: 0; opacity: 1; }

.ssp-auth-card .st-h-a {
    background: linear-gradient(90deg, rgba(196, 142, 90, .15), #c08b57, rgba(196, 142, 90, .15));
}
.ssp-auth-card .st-h-b {
    background: linear-gradient(90deg, rgba(196, 142, 90, .1), rgba(192, 139, 87, .6), rgba(196, 142, 90, .1));
}
/* The third horizon band belongs to the header lockup, not to this card. */
.ssp-auth-card .st-h-c { display: none; }

.st-logo-tag {
    display: block;
    margin-top: 17px;
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: .16em;
    line-height: 1.45;
    text-transform: uppercase;
    color: rgba(233, 230, 230, .66);
}
/* Sized to hold the tagline on one line down to a 320 px screen. A centred
   two-line wrap of a letterspaced caption reads as a mistake rather than as
   a line break. */
.ssp-auth-card .st-logo-tag {
    font-size: clamp(8px, 2.4vw, 10.5px);
    letter-spacing: clamp(.07em, .3vw, .16em);
    text-wrap: balance;
}

/* -------------------------------------------------------------------------
 * The field
 *
 * The caption sits above the control and stays there. It is not a floating
 * label, and that is the point.
 *
 * A floating label is driven by :placeholder-shown, and that selector is not
 * reliable for the one case this screen meets constantly: a browser filling
 * the email and password itself. Chromium does not always re-evaluate
 * :placeholder-shown for an autofilled value until the user touches the
 * control, so the caption stays sitting on the line where the autofilled text
 * has just been painted and the two overlap. Returning from the register pane
 * makes it worse, because coming back to a pane the browser has already seen
 * is exactly when it offers to fill it.
 *
 * A caption that never moves cannot collide with a value, whatever the browser
 * does, and it also matches the reference design, where every field carries a
 * standing caption over a shaded box with a rule beneath it.
 * ---------------------------------------------------------------------- */
.ssp-gfield {
    margin-top: clamp(16px, 2.4vh, 20px);
}
[data-pane] > .ssp-gfield:first-child { margin-top: clamp(20px, 3vh, 26px); }

/* The caption. `display: block` and its own margin, so the gap between the
   caption and the value is a stated distance rather than whatever the line
   boxes happen to leave. */
.ssp-gfield > label {
    display: block;
    margin: 0 0 7px;
    font-family: inherit;
    font-weight: 500;
    font-size: 12.5px;
    line-height: 1.35;
    letter-spacing: .01em;
    /* Raised from .72 with the card: a caption is the label of the control it
       sits over and has to clear 4.5:1 against the lightest place the glass
       can land on. */
    color: rgba(255, 255, 255, .84);
    text-shadow: 0 1px 2px rgba(0, 0, 0, .35);
}

/* The control row: the input, and the reveal button when there is one. The
   rule belongs to this box rather than to the input, because a generic
   `border: none !important` elsewhere in the document can erase an input
   border and cannot touch this one. */
.ssp-gbox {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 44px;                 /* a real touch target, gloves included */
    padding: 5px 10px 7px;
    border-radius: 8px 8px 0 0;
    /* Slightly stronger than it was, because the card beneath it is now
       translucent: a 3.5% white wash that read as a panel over an opaque card
       disappears over a photograph. */
    background: rgba(255, 255, 255, .07);
    border-bottom: 1px solid rgba(255, 255, 255, .55);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06);
    transition: border-color .15s ease, background .15s ease;
}
.ssp-gbox:focus-within {
    border-bottom-color: #ffffff;
    background: rgba(255, 255, 255, .11);
}

.ssp-gbox input {
    flex: 1 1 auto;
    min-width: 0;                     /* or a long value pushes the button out */
    width: 100%;
    height: 30px;
    padding: 0;
    color: #ffffff;
    font-family: inherit;
    font-weight: 400;
    /* 16 px is a floor, not a preference: below it mobile Safari zooms the
       whole page on focus and the card jumps out of the viewport. */
    font-size: 16px;
    line-height: 30px;
    outline: none;
}
.ssp-gbox input::placeholder { color: rgba(255, 255, 255, .34); }

/* Autofill. Every state is listed: Chromium paints its own background on
   hover and while active as well, and a rule that names only the base state
   leaves the pale blue block visible over a dark card. */
.ssp-gbox input:-webkit-autofill,
.ssp-gbox input:-webkit-autofill:hover,
.ssp-gbox input:-webkit-autofill:focus,
.ssp-gbox input:-webkit-autofill:active {
    -webkit-text-fill-color: #ffffff;
    caret-color: #ffffff;
    -webkit-box-shadow: 0 0 0 1000px rgba(40, 33, 28, 0) inset;
    box-shadow: 0 0 0 1000px rgba(40, 33, 28, 0) inset;
    transition: background-color 9999s ease-out 0s;
}

.ssp-gpeek {
    flex: 0 0 auto;
    align-self: stretch;
    min-height: 30px;
    padding: 0 2px;
    border: 0;
    background: transparent;
    color: rgba(255, 255, 255, .8);
    font-family: inherit;
    font-weight: 600;
    font-size: 11.5px;
    letter-spacing: .8px;
    text-transform: uppercase;
    white-space: nowrap;
    cursor: pointer;
}
.ssp-gpeek:hover { color: #ffffff; }
.ssp-gpeek:focus-visible {
    outline: 2px solid rgba(255, 255, 255, .7);
    outline-offset: 2px;
    border-radius: 3px;
}

/* -------------------------------------------------------------------------
 * Row, checkbox, links
 * ---------------------------------------------------------------------- */
.ssp-auth-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 10px 14px;
    margin: 26px 0;
}

.ssp-gcheck {
    display: inline-flex;
    align-items: center;
    gap: 11px;
    cursor: pointer;
    font-family: inherit;
    font-weight: 400;
    font-size: 13.5px;
    line-height: 1.2;
    color: #ffffff;
    text-shadow: 0 1px 2px rgba(0, 0, 0, .4);
}
.ssp-gcheck input {
    width: 17px;
    height: 17px;
    accent-color: #ffffff;
    cursor: pointer;
    flex: 0 0 auto;
}

.ssp-glink {
    border: 0;
    background: transparent;
    padding: 4px 0;
    color: #ffffff;
    text-shadow: 0 1px 2px rgba(0, 0, 0, .4);
    font-family: inherit;
    font-weight: 400;
    font-size: 13px;
    line-height: 1.4;
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
}
.ssp-glink:hover { color: #ffffff; }

/* -------------------------------------------------------------------------
 * Primary action
 * ---------------------------------------------------------------------- */
.ssp-gbtn {
    display: block;
    width: 100%;
    margin-top: 26px;
    min-height: 50px;
    padding: 15px;
    border: 0;
    border-radius: 7px;
    background: #ffffff;
    color: #1a1512;
    font-family: inherit;
    font-weight: 600;
    font-size: 15px;
    line-height: 1.2;
    cursor: pointer;
    box-shadow: 0 2px 10px rgba(0, 0, 0, .3);
    transition: transform .08s ease, background .15s ease;
}
.ssp-gbtn:hover { background: #f1f3f6; }
.ssp-gbtn:active { transform: translateY(1px); }
.ssp-gbtn:disabled { opacity: .55; cursor: default; }
.ssp-auth-row + .ssp-gbtn { margin-top: 0; }

/* The caption under the action. */
.ssp-auth-mode {
    margin: 17px 0 0;
    text-align: center;
    font-family: inherit;
    font-weight: 600;
    font-size: 10.5px;
    line-height: 1.4;
    letter-spacing: 1.3px;
    text-transform: uppercase;
    color: rgba(255, 255, 255, .7);
    text-shadow: 0 1px 2px rgba(0, 0, 0, .35);
}

.ssp-auth-foot-link {
    margin: 19px 0 0;
    text-align: center;
    font-family: inherit;
    font-weight: 400;
    font-size: 13.5px;
    line-height: 1.5;
    color: rgba(255, 255, 255, .95);
    text-shadow: 0 1px 2px rgba(0, 0, 0, .4);
}

.ssp-auth-hint {
    margin: 9px 0 0;
    font-family: inherit;
    font-weight: 400;
    font-size: 12.5px;
    line-height: 1.55;
    color: rgba(255, 255, 255, .74);
    text-shadow: 0 1px 2px rgba(0, 0, 0, .35);
    text-wrap: pretty;
}

/* -------------------------------------------------------------------------
 * Messages and status
 * ---------------------------------------------------------------------- */
.ssp-auth-msg {
    margin: 18px 0 0;
    padding: 10px 12px;
    border: 1px solid rgba(255, 255, 255, .16);
    border-radius: 10px;
    font-family: inherit;
    font-weight: 500;
    font-size: 13.5px;
    line-height: 1.45;
    /* A validation message is the one thing on this card that must never be
       hard to read, so it is opaque rather than glass. An error the user
       cannot make out is the same as no error at all. */
    background: rgba(38, 30, 25, .92);
    color: #ffffff;
}
.ssp-auth-msg:empty { display: none; }
.ssp-auth-msg.is-error {
    background: rgba(112, 30, 24, .94);
    border-color: rgba(255, 160, 150, .34);
    color: #ffe9e6;
}
.ssp-auth-msg.is-ok {
    background: rgba(19, 78, 45, .94);
    border-color: rgba(140, 226, 178, .32);
    color: #e6fff1;
}
.ssp-auth-msg.is-info {
    background: rgba(38, 30, 25, .92);
    border-color: rgba(255, 255, 255, .16);
}

.ssp-auth-status {
    margin-top: 22px;
    padding-top: 17px;
    border-top: 1px solid rgba(255, 255, 255, .16);
    text-align: center;
}
.ssp-conn {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-family: inherit;
    font-weight: 500;
    font-size: 12.5px;
    line-height: 1.4;
    color: #ffffff;
}
.ssp-conn::before {
    content: "";
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: rgba(255, 255, 255, .35);
    flex: 0 0 auto;
}
.ssp-conn.is-ok::before    { background: #3ea76a; }
.ssp-conn.is-warn::before  { background: #f0c27a; }
.ssp-conn.is-error::before { background: #e0655a; }
.ssp-conn.is-error { color: #ffb3ab; }

/* -------------------------------------------------------------------------
 * Password strength, measured against the rule the code enforces
 * ---------------------------------------------------------------------- */
.ssp-gmeter {
    margin: 12px 0 0;
    display: flex;
    align-items: center;
    gap: 10px;
}
.ssp-gmeter[hidden] { display: none; }
.ssp-gmeter-bar {
    flex: 0 0 84px;
    height: 4px;
    border-radius: 2px;
    background: rgba(255, 255, 255, .22);
    overflow: hidden;
}
.ssp-gmeter-bar i {
    display: block;
    height: 100%;
    width: 0;
    border-radius: 2px;
    transition: width .18s ease, background .18s ease;
}
.ssp-gmeter-text {
    font-family: inherit;
    font-weight: 400;
    font-size: 12px;
    line-height: 1.4;
    color: rgba(255, 255, 255, .72);
}
.ssp-gmeter.is-weak   .ssp-gmeter-bar i { background: #e88a80; }
.ssp-gmeter.is-ok     .ssp-gmeter-bar i { background: #f0c27a; }
.ssp-gmeter.is-strong .ssp-gmeter-bar i { background: #6fdc9a; }

/* -------------------------------------------------------------------------
 * Narrow and short screens
 *
 * Two breakpoints, both doing work the clamps above cannot: tightening the
 * field's reserved caption band on very small phones, and dropping the card's
 * vertical rhythm when the viewport is shorter than the register pane.
 * ---------------------------------------------------------------------- */
@media (max-width: 380px) {
    /* The tagline is one line or it is a mistake. At 320 px the card has about
       248 px of inner width, which the caption clears only once the tracking
       comes down with it. */
    .ssp-auth-card .st-logo-tag { font-size: 8px; letter-spacing: .04em; }
    .ssp-gbox { padding: 5px 8px 7px; gap: 8px; }
    .ssp-gfield > label { font-size: 12px; margin-bottom: 6px; }
    .ssp-gpeek { font-size: 11px; letter-spacing: .6px; }
}

@media (max-height: 720px) {
    .ssp-gfield { margin-top: 13px; }
    [data-pane] > .ssp-gfield:first-child { margin-top: 17px; }
    .ssp-gfield > label { margin-bottom: 5px; }
    .ssp-gbox { min-height: 40px; padding: 4px 10px 6px; }
    .ssp-gbox input { height: 28px; line-height: 28px; }
    .ssp-auth-row { margin: 18px 0; }
    .ssp-gbtn { margin-top: 18px; }
    .ssp-auth-hint { margin-top: 7px; }
    .ssp-auth-status { margin-top: 16px; padding-top: 13px; }
}

@media (prefers-reduced-motion: reduce) {
    .ssp-gbox, .ssp-gbox input,
    .ssp-gbtn, .ssp-gmeter-bar i { transition: none; }
}

/* =============================================================================
 * Full-screen panels: chooser, team, conflicts
 *
 * The same glass treatment as the sign-in card, over a plain dark backdrop
 * rather than the photograph. These panels open on top of a working map, so a
 * second full-bleed image behind them would fight the one already on screen.
 *
 * Everything shares the sign-in vocabulary: white type, hairline dividers at
 * low opacity, a solid white primary button, and a single accent for anything
 * that needs attention.
 * ========================================================================== */
.ssp-screen {
    position: fixed;
    inset: 0;
    z-index: var(--z-panel);
    background: linear-gradient(170deg, rgba(14, 20, 30, 0.94), rgba(9, 13, 20, 0.96));
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: 20px 16px calc(24px + env(safe-area-inset-bottom, 0px));
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    color: #ffffff;
}
.ssp-screen[hidden] { display: none; }

.ssp-screen-card {
    width: 100%;
    max-width: 640px;
    border-radius: 12px;
    border: 1px solid rgba(255, 255, 255, 0.22);
    background: rgba(255, 255, 255, 0.07);
    backdrop-filter: blur(18px) saturate(1.15);
    -webkit-backdrop-filter: blur(18px) saturate(1.15);
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.45);
    overflow: hidden;
    color: #ffffff;
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .ssp-screen-card { background: rgba(18, 24, 34, 0.94); }
}

.ssp-screen-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 14px;
    padding: 24px 26px 18px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.16);
}
.ssp-screen-head h2 {
    margin: 0;
    font: 800 24px/1.2 system-ui, -apple-system, "Segoe UI", sans-serif;
    color: #ffffff;
}
.ssp-screen-sub {
    margin: 5px 0 0;
    font: 500 11.5px/1.4 system-ui, sans-serif;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.6);
}
.ssp-screen-body { padding: 22px 26px 26px; }

/* -------------------------------------------------------------------------
 * Buttons, matching the sign-in card
 * ---------------------------------------------------------------------- */
.ssp-btn {
    width: 100%;
    min-height: 48px;
    padding: 0 18px;
    border: 1px solid rgba(255, 255, 255, 0.28);
    border-radius: 6px;
    background: rgba(255, 255, 255, 0.1);
    color: #ffffff;
    font: 600 15px/1 system-ui, sans-serif;
    cursor: pointer;
    transition: background .15s ease;
}
.ssp-btn:hover { background: rgba(255, 255, 255, 0.18); }
.ssp-btn:disabled { opacity: .45; cursor: default; }
.ssp-btn:active { transform: translateY(1px); }
.ssp-btn:focus-visible { outline: 2px solid #ffffff; outline-offset: 2px; }

.ssp-btn-primary {
    background: #ffffff;
    border-color: #ffffff;
    color: #16202c;
    font-weight: 700;
}
.ssp-btn-primary:hover { background: #f1f3f6; }

.ssp-btn-quiet {
    background: transparent;
    border-color: transparent;
    color: rgba(255, 255, 255, 0.85);
    text-decoration: underline;
    text-underline-offset: 3px;
}
.ssp-btn-quiet:hover { background: rgba(255, 255, 255, 0.08); }

.ssp-btn-danger {
    border-color: rgba(255, 140, 130, 0.45);
    background: rgba(255, 92, 77, 0.14);
    color: #ffb3ab;
}
.ssp-btn-small { min-height: 38px; width: auto; padding: 0 14px; font-size: 13.5px; }
.ssp-screen-head .ssp-btn { width: auto; margin: 0; }

/* -------------------------------------------------------------------------
 * Project list
 * ---------------------------------------------------------------------- */
.ssp-list { display: flex; flex-direction: column; gap: 10px; margin-bottom: 22px; }
.ssp-list-item {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
    width: 100%;
    min-height: 64px;
    padding: 14px 16px;
    border: 1px solid rgba(255, 255, 255, 0.2);
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.06);
    color: #ffffff;
    text-align: left;
    cursor: pointer;
    transition: background .15s ease, border-color .15s ease;
}
.ssp-list-item:hover { background: rgba(255, 255, 255, 0.12); border-color: rgba(255, 255, 255, 0.36); }
.ssp-list-title { font: 700 17px/1.3 system-ui, sans-serif; color: #ffffff; }
.ssp-list-meta {
    font: 500 11.5px/1.4 system-ui, sans-serif;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.58);
}

/* A project and its delete control on one line.
   The row is the target for opening; the control beside it is deliberately
   smaller and quieter, because the common action is opening a project and the
   rare one is destroying it. */
.ssp-list-row { display: flex; align-items: stretch; gap: 8px; }
.ssp-list-row .ssp-list-item { flex: 1; min-width: 0; }
.ssp-list-row .ssp-list-title,
.ssp-list-row .ssp-list-meta { max-width: 100%; overflow-wrap: anywhere; }

.ssp-list-del {
    flex: 0 0 auto;
    width: 48px;
    border: 1px solid rgba(255, 255, 255, 0.16);
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.04);
    color: rgba(255, 255, 255, 0.5);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.ssp-list-del svg { width: 20px; height: 20px; }
/* Red on approach only. A permanently red control in a list of projects reads
   as a warning about the projects rather than about the button. */
.ssp-list-del:hover,
.ssp-list-del:focus-visible {
    background: rgba(216, 30, 63, 0.16);
    border-color: rgba(216, 30, 63, 0.55);
    color: #ff8a9c;
}

/* The row layout itself lives with the picker further down; only the delete
   control's width is set here, beside the control it sizes. */
.ssp-picker-line .ssp-list-del { width: 44px; }

/* -------------------------------------------------------------------------
 * Delete confirmation
 * ---------------------------------------------------------------------- */
/* Above every other layer, by name rather than by out-bidding them. */
.ssp-confirm { z-index: var(--z-confirm); }
.ssp-confirm-card {
    max-width: 520px;
    max-height: min(90vh, 90dvh);
    display: flex;
    flex-direction: column;
}
/* The body scrolls, the header and the buttons do not. On a small screen the
   list of what will be erased is long enough to push the buttons off, and a
   confirmation whose confirm button cannot be reached is not one. */
.ssp-confirm-card .ssp-screen-body {
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    padding: 20px;
}
.ssp-confirm-card .ssp-screen-head { flex: 0 0 auto; padding: 20px 20px 0; }

/* Nothing behind the dialog moves. A fixed overlay does not stop the page
   underneath scrolling under a thumb on iOS, which is how a confirmation ends
   up floating over a map that is still panning. */
body.ssp-confirm-open { overflow: hidden; }

/* The buttons sit together at the end, cancel first. The destructive one is
   last because that is the position a thumb reaches deliberately rather than
   by momentum, and it is the wider of the two only in what it says. */
.ssp-confirm-card .ssp-row {
    display: flex;
    gap: 10px;
    margin-top: 4px;
}
.ssp-confirm-card .ssp-row .ssp-btn { flex: 1; margin: 0; }

.ssp-confirm-name {
    margin: 0 0 16px;
    padding: 12px 14px;
    border-left: 3px solid #d81e3f;
    background: rgba(255, 255, 255, 0.06);
    border-radius: 0 8px 8px 0;
    font: 700 18px/1.3 system-ui, sans-serif;
    color: #ffffff;
    overflow-wrap: anywhere;
}

.ssp-confirm-list {
    margin: 0 0 14px;
    padding-left: 18px;
    font: 400 13.5px/1.55 system-ui, sans-serif;
    color: rgba(255, 255, 255, 0.72);
}
.ssp-confirm-list li { margin-bottom: 5px; }

.ssp-confirm-warn {
    margin: 0 0 16px;
    padding: 10px 12px;
    border: 1px solid rgba(216, 30, 63, 0.45);
    border-radius: 8px;
    background: rgba(216, 30, 63, 0.1);
    font: 600 13.5px/1.5 system-ui, sans-serif;
    color: #ff8a9c;
}

@media (max-width: 560px) {
    .ssp-confirm { padding: 0; align-items: flex-end; }
    .ssp-confirm-card {
        max-width: none;
        max-height: min(92vh, 92dvh);
        border-radius: 18px 18px 0 0;
        padding-bottom: env(safe-area-inset-bottom);
    }
    /* Stacked, so neither label is truncated, and the destructive one still
       comes last in reading order. */
    .ssp-confirm-card .ssp-row { flex-direction: column-reverse; }
}

/* Disabled until the name has been typed, and it looks disabled. A destructive
   button that is styled as ready before it is ready invites the click it is
   meant to slow down. */
.ssp-btn-danger {
    background: #d81e3f;
    border-color: #d81e3f;
    color: #ffffff;
}
.ssp-btn-danger:hover:not(:disabled) { background: #b4162f; border-color: #b4162f; }
.ssp-btn-danger:disabled {
    background: rgba(255, 255, 255, 0.08);
    border-color: rgba(255, 255, 255, 0.16);
    color: rgba(255, 255, 255, 0.38);
    cursor: not-allowed;
}

/* -------------------------------------------------------------------------
 * Disclosure sections
 * ---------------------------------------------------------------------- */
.ssp-disclosure {
    border: 1px solid rgba(255, 255, 255, 0.2);
    border-radius: 10px;
    padding: 0 16px;
    margin-bottom: 12px;
    background: rgba(255, 255, 255, 0.04);
}
.ssp-disclosure > summary {
    min-height: 52px;
    display: flex;
    align-items: center;
    font: 600 15.5px/1.2 system-ui, sans-serif;
    color: #ffffff;
    cursor: pointer;
    list-style: none;
}
.ssp-disclosure > summary::-webkit-details-marker { display: none; }
.ssp-disclosure > summary::after {
    content: "+";
    margin-left: auto;
    font-size: 20px;
    font-weight: 300;
    color: rgba(255, 255, 255, 0.6);
}
.ssp-disclosure[open] > summary::after { content: "\2212"; }
.ssp-disclosure[open] { padding-bottom: 16px; }

.ssp-section { margin-bottom: 30px; }
.ssp-section:last-child { margin-bottom: 0; }
.ssp-section h3 {
    margin: 0 0 12px;
    font: 700 11.5px/1.3 system-ui, sans-serif;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.6);
}

/* -------------------------------------------------------------------------
 * Fields inside panels, matching the sign-in underline treatment
 * ---------------------------------------------------------------------- */
.ssp-field { margin-bottom: 22px; }
.ssp-field > span {
    display: block;
    margin-bottom: 7px;
    font: 600 12px/1.3 system-ui, sans-serif;
    color: rgba(255, 255, 255, 0.85);
}
.ssp-field input,
.ssp-field select,
.ssp-field textarea {
    width: 100%;
    min-height: 46px;
    padding: 10px 12px;
    border: 1px solid rgba(255, 255, 255, 0.24);
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.07);
    color: #ffffff;
    font: 400 16px/1.3 system-ui, sans-serif;
    outline: none;
}
.ssp-field input::placeholder, .ssp-field textarea::placeholder {
    color: rgba(255, 255, 255, 0.45);
}
.ssp-field input:focus,
.ssp-field select:focus,
.ssp-field textarea:focus {
    border-color: #ffffff;
    background: rgba(255, 255, 255, 0.12);
}
.ssp-field select option { background: #16202c; color: #ffffff; }
.ssp-field small {
    display: block;
    margin-top: 6px;
    font: 400 12px/1.5 system-ui, sans-serif;
    color: rgba(255, 255, 255, 0.58);
}

/* -------------------------------------------------------------------------
 * Progress figures
 * ---------------------------------------------------------------------- */
.ssp-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
    gap: 10px;
    margin: 0;
}
.ssp-stats > div {
    border: 1px solid rgba(255, 255, 255, 0.18);
    border-radius: 10px;
    padding: 12px 14px;
    background: rgba(255, 255, 255, 0.05);
}
.ssp-stats dt {
    font: 600 10.5px/1.3 system-ui, sans-serif;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.58);
}
.ssp-stats dd {
    margin: 6px 0 0;
    font: 800 24px/1.1 system-ui, sans-serif;
    color: #ffffff;
    font-variant-numeric: tabular-nums;
}

/* -------------------------------------------------------------------------
 * Tables
 * ---------------------------------------------------------------------- */
.ssp-table {
    width: 100%;
    border-collapse: collapse;
    margin-top: 12px;
    font: 400 14px/1.4 system-ui, sans-serif;
    color: rgba(255, 255, 255, 0.92);
}
.ssp-table th, .ssp-table td {
    padding: 10px 8px;
    text-align: left;
    border-bottom: 1px solid rgba(255, 255, 255, 0.14);
}
.ssp-table thead th {
    font: 700 10.5px/1.3 system-ui, sans-serif;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.55);
}
.ssp-table tr.is-dead { opacity: .45; }
.ssp-table code {
    font: 700 14px/1 ui-monospace, Menlo, Consolas, monospace;
    letter-spacing: 1.5px;
    color: #ffffff;
}

/* -------------------------------------------------------------------------
 * Members and roles
 * ---------------------------------------------------------------------- */
.ssp-members { display: flex; flex-direction: column; gap: 10px; }
.ssp-member {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    padding: 12px 14px;
    border: 1px solid rgba(255, 255, 255, 0.18);
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.05);
}
.ssp-member-id { flex: 1 1 180px; display: flex; flex-direction: column; color: #ffffff; }
.ssp-member-id span { font: 400 12.5px/1.3 system-ui, sans-serif; color: rgba(255, 255, 255, 0.6); }
.ssp-role {
    min-height: 42px;
    padding: 6px 10px;
    border: 1px solid rgba(255, 255, 255, 0.24);
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.07);
    color: #ffffff;
    font-size: 15px;
}
.ssp-role option { background: #16202c; color: #ffffff; }
.ssp-badge {
    padding: 5px 11px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.14);
    font: 700 11px/1 system-ui, sans-serif;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.9);
}
.ssp-rolehelp {
    margin: 10px 0 0;
    padding-left: 18px;
    font: 400 13.5px/1.7 system-ui, sans-serif;
    color: rgba(255, 255, 255, 0.7);
}
.ssp-rolehelp strong { color: #ffffff; }

.ssp-row { display: flex; gap: 12px; flex-wrap: wrap; }
.ssp-row > * { flex: 1 1 160px; }

.ssp-field textarea { min-height: 76px; resize: vertical; }

.ssp-note, .ssp-muted {
    font: 400 12.5px/1.55 system-ui, sans-serif;
    color: rgba(255, 255, 255, 0.6);
}
.ssp-error { color: #ffb3ab; font: 600 14px/1.5 system-ui, sans-serif; }

/* =============================================================================
 * Synchronisation chip
 *
 * This was a full-width band pinned to the bottom of the screen, sitting on
 * top of controls the application had already placed there: the save button
 * and layer button at bottom 96px, and the undo and clear pills at bottom
 * 16px. A band across the bottom of a map application will always collide with
 * something, because that is where map applications put their primary actions.
 *
 * It is now a chip in the bottom right corner. It shows two things without
 * being tapped, because both are things a field worker needs at a glance and
 * neither is worth a tap: which project they are recording into, and whether
 * their work has reached the server. Everything else lives in the panel.
 * ========================================================================== */
.ssp-syncbar {
    position: fixed;
    right: 16px;
    bottom: calc(16px + env(safe-area-inset-bottom, 0px));
    /* Above the map controls (560), below any modal. */
    z-index: 900;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 8px;
    max-width: min(320px, 60vw);
    pointer-events: none;
}
.ssp-syncbar > * { pointer-events: auto; }
.ssp-syncbar[hidden] { display: none; }

.ssp-syncchip {
    display: flex;
    align-items: center;
    gap: 9px;
    max-width: 100%;
    min-height: 46px;
    padding: 6px 12px 6px 13px;
    border: 1px solid #2c4c39;
    border-radius: 14px;
    background: rgba(18, 38, 28, 0.93);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.35);
    cursor: pointer;
    text-align: left;
    overflow: hidden;
}
.ssp-syncchip:active { background: rgba(26, 53, 39, 0.97); }

.ssp-chip-lines {
    display: flex;
    flex-direction: column;
    min-width: 0;
    gap: 1px;
}

/* The project name is the primary line. It is the answer to "which campaign
   am I recording into", which must never require a tap. */
.ssp-chip-project {
    font: 700 13px/1.25 system-ui, sans-serif;
    color: #f0f6f2;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The save state is the secondary line, with the time, because "saved" without
   a time tells you nothing about whether it was saved before or after the last
   record you entered. */
.ssp-syncbar-state {
    font: 500 11.5px/1.25 system-ui, sans-serif;
    color: #9dbcaa;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ssp-chip-caret {
    flex: 0 0 auto;
    width: 0; height: 0;
    margin-left: 2px;
    border-left: 4.5px solid transparent;
    border-right: 4.5px solid transparent;
    border-bottom: 5px solid #7e9a89;
    transition: transform 140ms ease;
}
.ssp-syncbar.is-open .ssp-chip-caret { transform: rotate(180deg); }
.ssp-syncbar.is-open .ssp-syncchip { border-color: #4a7f5e; }

/* -------------------------------------------------------------------------
 * State colouring. The whole chip carries it, so an offline or conflicted
 * chip is legible at arm's length without reading the words.
 * ---------------------------------------------------------------------- */
.ssp-dot {
    flex: 0 0 10px;
    width: 10px; height: 10px;
    border-radius: 50%;
    background: #7f8f86;
}
.ssp-dot.is-idle     { background: #3fa06a; }
.ssp-dot.is-syncing  { background: #d3a11f; animation: ssp-pulse 1.1s ease-in-out infinite; }
.ssp-dot.is-offline  { background: #d08a2a; }
.ssp-dot.is-error    { background: #e05252; }
.ssp-dot.is-conflict { background: #e05252; animation: ssp-pulse .8s ease-in-out infinite; }

.ssp-syncbar.is-state-offline .ssp-syncchip  { border-color: #7a5417; background: rgba(48, 33, 12, 0.93); }
.ssp-syncbar.is-state-offline .ssp-syncbar-state { color: #f0c27a; }
.ssp-syncbar.is-state-error .ssp-syncchip,
.ssp-syncbar.is-state-conflict .ssp-syncchip  { border-color: #8a2b2b; background: rgba(56, 20, 20, 0.94); }
.ssp-syncbar.is-state-error .ssp-syncbar-state,
.ssp-syncbar.is-state-conflict .ssp-syncbar-state { color: #ffb3ab; }

@keyframes ssp-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .3; } }
@media (prefers-reduced-motion: reduce) {
    .ssp-dot { animation: none !important; }
}

/* -------------------------------------------------------------------------
 * The expanded panel
 * ---------------------------------------------------------------------- */
.ssp-syncpanel {
    width: min(292px, 80vw);
    padding: 12px;
    border: 1px solid #2c4c39;
    border-radius: 14px;
    background: rgba(18, 38, 28, 0.97);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
}
.ssp-syncpanel[hidden] { display: none; }

.ssp-syncpanel-project {
    font: 700 15px/1.3 system-ui, sans-serif;
    color: #eaf3ec;
    margin-bottom: 4px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.ssp-syncpanel-detail {
    font: 400 12.5px/1.5 system-ui, sans-serif;
    color: #a8c0b0;
    margin-bottom: 10px;
}
.ssp-syncpanel-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
    margin-bottom: 8px;
}

.ssp-syncbar-btn {
    min-height: 42px;
    padding: 0 12px;
    border: 1px solid #2c4c39;
    border-radius: 9px;
    background: #1a3527;
    color: #dceadf;
    font: 600 14px/1 system-ui, sans-serif;
    cursor: pointer;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.ssp-syncbar-btn:active { background: #23472f; }
.ssp-syncbar-wide { width: 100%; }

@media (max-width: 420px) {
    .ssp-syncbar { right: 12px; bottom: calc(12px + env(safe-area-inset-bottom, 0px)); max-width: 64vw; }
    .ssp-chip-project { font-size: 12.5px; }
    .ssp-syncbar-state { font-size: 11px; }
}

/* =============================================================================
 * Conflict comparison
 * ========================================================================== */
.ssp-conflict {
    border: 1px solid rgba(255, 255, 255, 0.2);
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.05);
    padding: 16px;
    margin-bottom: 18px;
}
.ssp-conflict h3 {
    margin: 0 0 8px;
    font: 700 17px/1.2 ui-monospace, Menlo, monospace;
    color: #ffffff;
}
.ssp-compare th {
    width: 34%;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.6);
}
/* The rows that actually differ are the reason this table exists, so they are
   the only thing given a colour. */
.ssp-compare tr.is-diff { background: rgba(240, 194, 122, 0.16); }
.ssp-compare tr.is-diff th { color: #f0c27a; }
.ssp-conflict .ssp-row .ssp-btn { flex: 1 1 140px; }

/* =============================================================================
 * Toast
 * ========================================================================== */
.ssp-toast {
    position: fixed;
    left: 50%;
    /* Top centre, not bottom. The bottom of the map view carries the save
       button, the layer button and the undo pills; a toast there covers the
       control the person is about to press. */
    top: calc(120px + env(safe-area-inset-top, 0px));
    transform: translate(-50%, -14px);
    z-index: 13000;
    max-width: min(92vw, 520px);
    padding: 13px 16px;
    border-radius: 10px;
    background: rgba(18, 24, 34, 0.95);
    border: 1px solid rgba(255, 255, 255, 0.18);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    color: #ffffff;
    font: 500 15px/1.45 system-ui, sans-serif;
    box-shadow: 0 10px 30px rgba(0, 0, 0, .3);
    opacity: 0;
    pointer-events: none;
    transition: opacity .18s ease, transform .18s ease;
}
.ssp-toast.is-visible { opacity: 1; transform: translate(-50%, 0); }
.ssp-toast.is-ok { background: rgba(23, 69, 46, 0.95); border-color: rgba(111, 220, 154, 0.4); }
.ssp-toast.is-warn { background: rgba(107, 66, 9, 0.95); border-color: rgba(240, 194, 122, 0.4); }
.ssp-toast.is-error { background: rgba(109, 26, 26, 0.95); border-color: rgba(255, 179, 171, 0.4); }

/* =============================================================================
 * Read-only state
 * ========================================================================== */
body.ssp-readonly [disabled] { opacity: .45; }
body.ssp-readonly::after {
    content: "Read-only access";
    position: fixed;
    top: 0; left: 50%;
    transform: translateX(-50%);
    z-index: 8500;
    padding: 3px 12px;
    border-radius: 0 0 8px 8px;
    background: #8a5b06;
    color: #fff;
    font: 600 12px/1.6 system-ui, sans-serif;
    pointer-events: none;
}

/* =============================================================================
 * Larger screens
 * ========================================================================== */
@media (min-width: 900px) {
    /* .ssp-auth is deliberately absent here. It centres through `margin: auto`
       on its card at every width, which behaves correctly when the pane is
       taller than the viewport; the align-items override that used to live
       here fought that and clipped the register pane. */
    .ssp-screen { align-items: center; padding: 32px; }
    .ssp-screen-card { max-height: 88vh; display: flex; flex-direction: column; }
    .ssp-screen-body { overflow-y: auto; }
    .ssp-btn { width: auto; min-width: 160px; margin-right: 8px; }
    .ssp-field { max-width: 100%; }
}


/* =============================================================================
 * Sampling design panel
 *
 * What was here was the styling for a summary card: a dark identification
 * panel with the field's area in three units, a row of measured-statistic
 * tiles, a list of design parameters each with a colour-coded badge saying
 * whether its value was measured, computed or conventional, a caution
 * paragraph and its own action row. Around three hundred lines of it.
 *
 * The card is gone from the markup, so the styling goes with it. Every number
 * it displayed is either an editable control in the form below it or a
 * property of a polygon the person drew and can see, which made the card a
 * restatement of the panel it sat on top of, at roughly the height of the
 * panel itself. Removing it is most of the reason the form is now short
 * enough to read on a phone.
 *
 * Three things survive, because they were doing work rather than restating:
 * the colour tokens, which the prior-variability block and the feasibility
 * list both use; the severity colours for warnings; and the mark on an input
 * the person has set by hand.
 * ========================================================================== */

/* =============================================================================
 * Layers
 *
 * Every overlay in this file had picked its own z-index, and the numbers had
 * drifted to within a few hundred of the 32-bit maximum: 2147483250 for the
 * project switcher, 2147483300 for the team dashboard, 2147483350 for the
 * export dialog. Numbers that large are not a scale, they are a record of
 * people needing to be above whatever was there before, and they stop meaning
 * anything the moment two of them are close together.
 *
 * That is not a tidiness complaint. The delete confirmation was written at
 * 100000, which reads as "very high" and is in fact twenty thousand times
 * below the switcher it was opened from, so the dialog appeared underneath the
 * panel that opened it and could not be reached.
 *
 * These five names are the whole scale. Anything that overlays the page picks
 * one. The gaps are wide enough to slot something in without renumbering, and
 * the top one is reserved for exactly what it says: a question that must be
 * answered before anything else can be touched.
 * ========================================================================== */
:root {
    --z-map-control: 900;      /* controls sitting on the map */
    --z-panel: 11500;          /* full-screen panels: projects, conflicts */
    --z-overlay: 12500;        /* dialogs opened from a panel: picker, country */
    --z-dashboard: 13500;      /* team dashboard and the export dialog */
    --z-confirm: 20000;        /* destructive confirmation. Nothing goes above. */
}

:root {
    --sd-ink: #22283a;
    --sd-ink-2: #2c3348;
    --sd-red: #d81e3f;
    --sd-red-dark: #b4162f;
    --sd-paper: #f2f3f5;
    --sd-line: #d9dce2;
    --sd-ok: #1f7a46;
}

/* A saved plan's cores, drawn from the parcel rather than from the working
   session. Slightly smaller and warmer than a working design point, so a
   committed plan reads as settled beside one still being adjusted. */
.saved-plan-core { cursor: default; }
/* A collected planned point. Green and clickable, because it opens the record
   it already has rather than offering a new collection. The colour difference
   is what stops someone walking to a location they have already sampled. */
.saved-plan-core.is-collected { cursor: pointer; }
.saved-plan-route { pointer-events: none; }

/* The polygon close target on the first vertex.
   Red against the amber of every other drawing element, because it means
   something different: not another corner, but the end of the shape. It pulses
   only once ready, so "you may finish now" and "keep going" look different at a
   glance without anyone reading the tooltip. */
.polygon-close-marker {
    cursor: pointer;
    filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.45));
}
.polygon-close-marker.is-ready {
    animation: ssp-close-pulse 1.6s ease-in-out infinite;
}
@keyframes ssp-close-pulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.62; }
}
/* Someone who prefers no motion still gets the colour and the tooltip. */
@media (prefers-reduced-motion: reduce) {
    .polygon-close-marker.is-ready { animation: none; }
}

.polygon-close-tooltip {
    background: #d81e3f !important;
    color: #ffffff !important;
    border: 2px solid rgba(255, 255, 255, 0.92) !important;
    border-radius: 999px !important;
    padding: 4px 10px !important;
    font: 700 12px/1 'Inter Tight', system-ui, sans-serif !important;
    white-space: nowrap !important;
    box-shadow: 0 5px 16px rgba(0, 0, 0, 0.35) !important;
    pointer-events: none !important;
}
.polygon-close-tooltip::before { border-top-color: #d81e3f !important; }

/* Whether a declared intent to compare management zones could be honoured.
   Sits above the feasibility box because it decides whether a whole design
   family is available, which is a bigger question than whether the numbers in
   it will fit. */
.sd-zone-notice { margin: 12px 0 0; font-size: 12px; line-height: 1.5; }
.sd-zone-notice[hidden] { display: none; }
.sd-zone-ok {
    margin: 0; padding: 9px 11px;
    border-left: 3px solid var(--sd-ok, #1f7a46);
    background: rgba(31, 122, 70, 0.08);
    border-radius: 0 8px 8px 0; color: #2f6b4a;
}
.sd-zone-warn {
    margin: 0; padding: 9px 11px;
    border-left: 3px solid #b8860b;
    background: rgba(184, 134, 11, 0.09);
    border-radius: 0 8px 8px 0; color: #7a5c06;
}
.sd-zone-rejected {
    margin: 6px 0 0; padding-left: 20px;
    font-size: 11.5px; line-height: 1.5; color: #8a7a55;
}

/* -------------------------------------------------------------------------
 * Feasibility
 *
 * Sits directly above Recalculate and Generate, because it describes whether
 * the values in the form can be satisfied and those are the two things a
 * person does about it. Hidden entirely when there is nothing to say: a box
 * that is always on screen is a box people stop reading.
 * ---------------------------------------------------------------------- */
.sd-feasibility {
    margin: 14px 0 0;
    padding: 10px 12px;
    background: #ffffff;
    border: 1px solid var(--sd-line);
    border-left: 3px solid var(--sd-red);
    border-radius: 0 10px 10px 0;
}
.sd-feasibility[hidden] { display: none; }

.sd-feasibility-list {
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: 12px;
    line-height: 1.5;
}
.sd-feasibility-list li {
    position: relative;
    padding: 5px 0 5px 16px;
    color: #4a5162;
}
.sd-feasibility-list li::before {
    content: "";
    position: absolute;
    left: 2px; top: 11px;
    width: 6px; height: 6px;
    border-radius: 50%;
    background: currentColor;
}

/* The consequence of the count and the buffer together, which is the one
   derived quantity not readable from either field on its own. */
.sd-feasibility-derived {
    margin: 8px 0 0;
    font-size: 11.5px;
    line-height: 1.5;
    color: #6b7385;
    font-variant-numeric: tabular-nums;
}
.sd-feasibility-list + .sd-feasibility-derived {
    padding-top: 8px;
    border-top: 1px solid #eceef2;
}

.sd-w-error { color: #a3141f; font-weight: 600; }
.sd-w-warn  { color: #8a5b06; }
.sd-w-note  { color: #6b7385; }

/* -------------------------------------------------------------------------
 * Recalculate
 *
 * Its own row, immediately above Generate plan, which is the order of the
 * work: the system proposes, the person adjusts, they recalculate if they
 * want the proposal back, then they generate. Secondary weight, because it
 * discards the person's own numbers and Generate does not.
 * ---------------------------------------------------------------------- */
.sd-recalc-row {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
    margin-top: 14px;
}
.sd-recalc-row[hidden] { display: none; }

#sd_recalcDefaults {
    min-height: 44px;
    width: 100%;
    font-size: 13px;
    font-weight: 700;
}

/* Stated next to the button that would discard them, not somewhere else. */
.sd-touched-hint {
    margin: 0;
    font-size: 11.5px;
    line-height: 1.45;
    color: #8a5b06;
    text-align: center;
}
.sd-touched-hint:empty { display: none; }


/* -------------------------------------------------------------------------
 * Prior variability inputs
 *
 * Three unlabelled boxes in a row invite the wrong number in the wrong box,
 * and nothing afterwards reveals the mistake. Each field carries its own
 * label, its unit, and a one-line hint about what belongs in it.
 * ---------------------------------------------------------------------- */
.sd-prior {
    padding: 14px;
    background: #ffffff;
    border: 1px solid var(--sd-line);
    border-left: 3px solid var(--sd-red);
    border-radius: 0 12px 12px 0;
}

.sd-prior-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 6px;
}
.sd-prior-title {
    font-size: 10.5px;
    font-weight: 800;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--sd-ink);
}
.sd-prior-flag {
    flex: 0 0 auto;
    font-size: 9.5px;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    padding: 3px 8px;
    border-radius: 999px;
    background: #eceef2;
    color: #6b7385;
}
.sd-prior-flag.is-active { background: var(--sd-ok); color: #ffffff; }

.sd-prior-intro {
    margin: 0 0 12px;
    font-size: 12px;
    line-height: 1.5;
    color: #6b7385;
}

.sd-prior-row {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
}

.sd-prior-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin: 0;
}
.sd-prior-label {
    font-size: 11px;
    font-weight: 700;
    color: var(--sd-ink);
    letter-spacing: 0.01em;
}
.sd-prior-input { position: relative; display: block; }
.sd-prior-input input,
.sd-prior-input select {
    width: 100%;
    min-height: 42px;
    padding: 0 26px 0 10px;
    border: 1px solid var(--sd-line);
    border-radius: 8px;
    background: #fbfbfc;
    color: var(--sd-ink);
    font: 700 15px/1 system-ui, sans-serif;
    font-variant-numeric: tabular-nums;
}
.sd-prior-input select { padding-right: 10px; }
.sd-prior-input input:focus,
.sd-prior-input select:focus {
    outline: 2px solid var(--sd-red);
    outline-offset: -1px;
    background: #ffffff;
}
/* The unit sits inside the box, so the number and its unit cannot be
   separated by a line break or misread as two fields. */
.sd-prior-input i {
    position: absolute;
    right: 10px; top: 50%;
    transform: translateY(-50%);
    font-style: normal;
    font-size: 12px;
    font-weight: 700;
    color: #9aa2b1;
    pointer-events: none;
}
.sd-prior-field small {
    font-size: 10.5px;
    line-height: 1.35;
    color: #8b93a3;
}

.sd-prior-warn {
    margin: 12px 0 0;
    padding: 9px 11px;
    border-radius: 8px;
    background: #fff5f6;
    border: 1px solid #f0c3ca;
    font-size: 11.5px;
    line-height: 1.5;
    color: #8a2230;
}
.sd-prior-warn[hidden] { display: none; }

/* A value entered by hand is marked, so it is obvious which numbers came from
   the field and which were chosen deliberately. */
input.sd-user-set {
    border-color: var(--sd-red) !important;
    background: #fff7f8 !important;
    box-shadow: inset 0 0 0 1px rgba(216, 30, 63, 0.3);
}

@media (max-width: 520px) {
    /* Three side by side leaves each about ninety pixels wide on a phone,
       which is not enough for a label and a numeric field. */
    .sd-prior-row { grid-template-columns: 1fr; }
}


/* =============================================================================
 * Sampling design panel shell
 *
 * .modal-card had no definition anywhere in the document, so the panel
 * rendered with no background at all and its text sat directly on the
 * satellite imagery.
 * ========================================================================== */
.modal-card {
    position: relative;
    /* Inside .modal, which isolates its stacking context, so 1 is enough to sit
       above the backdrop. The near-maximum value it had was doing nothing that
       this does not, and it made the card look like a top-level layer. */
    z-index: 1;
    background: var(--card, rgba(255, 255, 255, 0.97));
    color: var(--text, #142217);
    border-radius: 18px;
    padding: 18px;
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.38);
    border: 1px solid rgba(20, 34, 23, 0.1);
    backdrop-filter: blur(14px) saturate(1.1);
    -webkit-backdrop-filter: blur(14px) saturate(1.1);
}
.modal-card h3, .modal-card .sd-title { margin: 0 0 12px; color: var(--text, #142217); }

/* =============================================================================
 * Map corner handles (js/map-editing.js)
 *
 * No toolbar. The back arrow and the clear cross already on screen carry every
 * action; these rules style only the corner handles themselves.
 * ========================================================================== */

/* The prompt on the first corner once the ring can be closed. */
.ssp-close-hint {
    background: rgba(31, 138, 61, 0.95) !important;
    color: #ffffff !important;
    border: none !important;
    font-weight: 700;
    font-size: 11px;
    padding: 3px 8px !important;
    border-radius: 6px !important;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35) !important;
    white-space: nowrap;
}
.ssp-close-hint::before { border-top-color: rgba(31, 138, 61, 0.95) !important; }

.ssp-vertex-handle { cursor: grab; }
.ssp-vertex-handle:active { cursor: grabbing; }
.ssp-midpoint-handle { cursor: copy; }

/* A selected corner pulses gently, so it is obvious which one the back arrow
   would remove. */
@keyframes ssp-selected-pulse {
    0%, 100% { stroke-opacity: 1; }
    50%      { stroke-opacity: 0.45; }
}
.leaflet-interactive.ssp-vertex-handle[stroke="#ffffff"] {
    animation: ssp-selected-pulse 1.4s ease-in-out infinite;
}

/* =============================================================================
 * Detail visibility (js/zoom-detail.js)
 *
 * An earlier version of this block hid vertex tooltips and distance badges
 * behind a stricter label threshold than the application had ever used. That
 * made things disappear that used to be visible, which is the opposite of the
 * problem being solved. Only the point number labels are gated here, and at a
 * threshold low enough that they appear well before the old fixed zoom rule
 * would have shown them.
 * ========================================================================== */

/* .saved-network-alt-label is gone with the sub-point circles it labelled: a
   saved sample no longer redraws the cores the design layer already shows. */

/* =============================================================================
 * The wordmark in the main interface
 *
 * The header sits over satellite imagery, so the mark carries its own contrast
 * rather than relying on the map beneath it. It is smaller and left-aligned
 * here, because in the working interface it is an identifier rather than the
 * subject of the screen.
 * ========================================================================== */
.st-logo-header {
    margin: 0;
    text-align: left;
    font-weight: 400;
}
.st-logo-header .st-logo-word {
    font-size: 21px;
    line-height: 1.05;
    text-shadow: 0 1px 6px rgba(0, 0, 0, 0.55);
}
.st-logo-header .st-soil  { color: rgba(255, 255, 255, 0.9); font-weight: 300; }
.st-logo-header .st-trace { color: #ffffff; font-weight: 800; }

.st-logo-header .st-logo-rule {
    width: 62px;
    margin: 6px 0 0;
    gap: 1.5px;
}
.st-logo-header .st-logo-rule i { height: 2px; }
.st-logo-header .st-h-a { background: #e6ddd2; }
.st-logo-header .st-h-b { background: #c99162; }
.st-logo-header .st-h-c { background: #e8c391; }

.st-logo-header .st-logo-tag {
    margin-top: 7px;
    font-size: 8.5px;
    letter-spacing: 0.14em;
    color: rgba(255, 255, 255, 0.62);
    text-shadow: 0 1px 4px rgba(0, 0, 0, 0.6);
}

/* The wordmark in the project chooser and team panels, which are dark. */
.ssp-screen .st-logo-word { font-size: 22px; }
.ssp-screen .st-h-a { background: #d9cfc4; }
.ssp-screen .st-h-b { background: #c08b5c; }
.ssp-screen .st-h-c { background: #e0b988; }

@media (max-width: 420px) {
    .st-logo-header .st-logo-word { font-size: 18px; }
    .st-logo-header .st-logo-tag { font-size: 8px; }
}

/* Inline wordmark above a panel heading. */
.st-logo-inline {
    text-align: left;
    margin-bottom: 12px;
}
.st-logo-inline .st-logo-word { font-size: 20px; }
.st-logo-inline .st-logo-rule { width: 56px; margin: 5px 0 0; gap: 1.5px; }
.st-logo-inline .st-logo-rule i { height: 2px; }

/* =============================================================================
 * The bottom control row
 *
 * Save, project management and team management used to float in the lower
 * right as a second cluster beside the centred tool row, which read as two
 * competing groups rather than one. They are ordinary members of the same row
 * now and inherit its button class, so size, shape, spacing, alignment, hover
 * and touch target all come from one place.
 *
 * Seven controls do not fit across a 320 px phone at the desktop size, so the
 * row adapts in three stages rather than one: the gap closes first, then the
 * glyph and the label shrink to a floor, and only then is the row allowed to
 * scroll sideways. Scrolling comes last because a control that has to be found
 * by swiping is worse than a small one, and it is there at all because
 * wrapping to a second line would cover the map and push the row off the
 * bottom edge on a handset held sideways.
 *
 * These rules sit at the end of the file and carry !important because the
 * row's geometry is set from several blocks in index.html that already do.
 * ========================================================================== */

body.map-tab-active .mockup-map-tools {
    /* Full width, symmetric. Insetting the row to clear the undo and clear
       pills cost it 88 px, which on a 390 px handset was the difference
       between seven controls fitting and seven controls needing a swipe. The
       pills move up out of the band instead: they are two small controls with
       the whole left edge of the map to sit in, and the row is the thing that
       has to be reachable without scrolling. */
    left: 8px !important;
    right: 8px !important;
    /* The row was centred with left:50% and a half-width translate. Spanning it
       edge to edge and centring the flex content instead is what lets it grow
       into a scroller when seven controls will not fit, but the old translate
       has to go with it or the whole row sits half a screen to the left. */
    transform: none !important;
    top: auto !important;
    bottom: calc(26px + env(safe-area-inset-bottom, 0px)) !important;
    width: auto !important;
    max-width: none !important;
    flex-direction: row !important;
    flex-wrap: nowrap !important;
    /* Centred, not bottom-aligned. The save control's ring is a different
       shape from the glyphs beside it, and aligning on the baseline of a row
       whose labels are hidden on phones just made it sit proud of the others. */
    align-items: center !important;
    /* Centred while it fits, start-aligned once it does not. A centred
       overflowing flex row cannot be scrolled back to its first item in any
       browser: the overflow spills off both ends and the left one is
       unreachable. `safe center` degrades to start at exactly that point. */
    /* Two declarations, in this order, on purpose. Safari before 16.4 does not
       understand the `safe` keyword and drops the whole declaration, which
       would leave the row on whatever alignment index.html set last. The plain
       keyword is the floor; the safe one is the improvement where it is
       understood. */
    justify-content: center !important;
    justify-content: safe center !important;
    gap: clamp(2px, 2.2vw, 22px) !important;
    padding: 2px 4px !important;
    overflow-x: auto !important;
    overflow-y: hidden !important;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
}
body.map-tab-active .mockup-map-tools::-webkit-scrollbar { display: none; }

body.map-tab-active .mockup-map-tools .map-tool-btn {
    flex: 0 0 auto !important;
    scroll-snap-align: center;
    /* The floor is a target that still works with cold hands, not the smallest
       thing that can legibly be drawn. */
    min-width: 52px !important;
    min-height: 52px !important;
}

/* The live position hint is a single thin line and it sat in the band the row
   now occupies, so the two crossed. It goes under the row rather than over it:
   the hint explains the locate control, so it belongs next to the controls,
   and it is the shorter of the two. */
body.map-tab-active .live-location-status {
    bottom: calc(5px + env(safe-area-inset-bottom, 0px)) !important;
    z-index: 730 !important;
}

/* The undo and clear pills move above the row for the same reason: the row
   needs the full width more than they need the corner. */
body.map-tab-active .map-selection-pills {
    left: 8px !important;
    right: auto !important;
    bottom: calc(92px + env(safe-area-inset-bottom, 0px)) !important;
    width: auto !important;
    justify-content: flex-start !important;
    z-index: 745 !important;
}
@media (max-height: 460px) {
    body.map-tab-active .map-selection-pills {
        bottom: calc(84px + env(safe-area-inset-bottom, 0px)) !important;
    }
}

/* The synchronisation state rides on the project control, so the row still
   answers "has my work reached the server" without being tapped. */
.tool-ico { position: relative; }
.tool-state-dot {
    position: absolute;
    right: -2px;
    top: -1px;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: #7f8f86;
    box-shadow: 0 0 0 2px rgba(0, 0, 0, .5);
    pointer-events: none;
}
.tool-state-dot.is-idle     { background: #3fa06a; }
.tool-state-dot.is-syncing  { background: #d3a11f; animation: ssp-pulse 1.1s ease-in-out infinite; }
.tool-state-dot.is-offline  { background: #d08a2a; }
.tool-state-dot.is-error    { background: #e05252; }
.tool-state-dot.is-conflict { background: #e05252; animation: ssp-pulse .8s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) {
    .tool-state-dot { animation: none !important; }
}

/* Narrow phones: close the gap and take the type to its floor before the row
   is allowed to scroll. */
@media (max-width: 560px) {
    /* Only where the row can actually overflow. A row that fits does not need
       an affordance, and the fade would dim the outermost control for nothing.
       Below 380 px seven controls cannot fit at any legible size, so the fade
       is telling the truth about there being more to the side. */
    @media (max-width: 380px) {
        body.map-tab-active .mockup-map-tools {
            -webkit-mask-image: linear-gradient(to right, transparent 0,
                #000 14px, #000 calc(100% - 14px), transparent 100%);
            mask-image: linear-gradient(to right, transparent 0,
                #000 14px, #000 calc(100% - 14px), transparent 100%);
        }
    }

    body.map-tab-active .mockup-map-tools {
        gap: 2px !important;
        bottom: calc(24px + env(safe-area-inset-bottom, 0px)) !important;
    }
    body.map-tab-active .mockup-map-tools .map-tool-btn {
        min-width: 50px !important;
        font-size: 9px !important;
    }
    body.map-tab-active .mockup-map-tools .tool-ico {
        font-size: 25px !important;
    }
    body.map-tab-active .mockup-map-tools .tool-ico svg {
        width: 25px !important;
        height: 25px !important;
    }
}

/* A handset in landscape has almost no height under the map, so the row moves
   closer to the edge. */
@media (max-height: 460px) {
    body.map-tab-active .mockup-map-tools {
        bottom: calc(22px + env(safe-area-inset-bottom, 0px)) !important;
    }
    body.map-tab-active .mockup-map-tools .map-tool-btn {
        min-height: 46px !important;
    }
}

/* The project chip stays where it is on a desktop, where there is room for it
   beside the row. On a phone the row already carries the project and team
   controls, so the chip would only be a third thing in the corner. */
@media (max-width: 820px), (max-height: 560px) {
    body.map-tab-active .ssp-syncchip { display: none; }
    body.map-tab-active .ssp-syncbar {
        right: 8px;
        bottom: calc(118px + env(safe-area-inset-bottom, 0px));
    }
    body.map-tab-active .ssp-syncpanel {
        width: min(300px, calc(100vw - 24px));
        max-height: calc(100vh - 200px);
        overflow-y: auto;
    }
}

/* =============================================================================
 * Session actions in the toolbox
 *
 * Sign out is not a map tool and is not laid out as one. It sits after a rule
 * at the end of the toolbox, so a thumb reaching for "clear polygon" cannot
 * land on it, and it is tinted rather than amber so it does not read as one
 * more drawing control.
 * ========================================================================== */
/* A full-width rule, not a vertical tick. The toolbox wraps, so a tick between
   two buttons ends up wherever the wrap happens to fall and separates nothing.
   Breaking the line puts the session action on a row of its own whatever the
   screen width, and `order` keeps it last even though the language toggle is
   appended to this container at run time, after it. */
.header-menu-sep {
    flex: 0 0 100%;
    order: 1;
    width: auto;
    height: 1px;
    margin: 7px 0 3px;
    background: rgba(255, 255, 255, .30);
    box-shadow: 0 1px 3px rgba(0, 0, 0, .45);
}
.header-layer-action.header-signout-action { order: 2; }
body:not(.map-tab-active) .header-menu-sep { display: none !important; }

/* index.html paints every .header-layer-action amber from a two-class
   selector later in the cascade, so the tint has to be stated with three. */
.header-layer-action.header-signout-action,
body.map-tab-active .header-layer-action.header-signout-action {
    color: #ff8b7a !important;
}
.header-layer-action.header-signout-action svg {
    width: 23px;
    height: 23px;
    stroke: currentColor;
    fill: none;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}
body.map-tab-active .header-layer-action.header-signout-action:hover,
body.map-tab-active .header-layer-action.header-signout-action:focus-visible,
.header-layer-action.header-signout-action:hover,
.header-layer-action.header-signout-action:focus-visible {
    color: #ffb1a4 !important;
}

/* =============================================================================
 * Refresh session
 *
 * It stands in the bottom left group with the undo and clear controls, above
 * the undo control, and takes that group's own metrics so its size, spacing,
 * hover and touch target cannot drift from its neighbours.
 *
 * It is on this side of the screen rather than the other because the save
 * control stands in the opposite corner and, on a small phone or a handset
 * held sideways, overlaps whatever else is there.
 * ========================================================================== */

/* The group draws its glyphs with ::before content, and the first and last
   child each get one by position. This control brings its own drawing, so both
   of those have to be turned off for it or it would be given the undo arrow as
   well. */
.map-selection-pills .pill-btn.refresh-pill::before,
.map-selection-pills .pill-btn.refresh-pill::after {
    content: none !important;
    display: none !important;
}

.map-selection-pills .pill-btn.refresh-pill {
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    /* A real target on a cold morning. The glyph inside stays the size of the
       glyphs beside it; only the transparent box is larger. */
    min-width: 44px !important;
    min-height: 44px !important;
}

.map-selection-pills .pill-btn.refresh-pill svg {
    width: 28px;
    height: 28px;
    display: block;
    stroke: currentColor;
    fill: none;
    filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.52));
}

.map-selection-pills .pill-btn.refresh-pill.is-busy {
    pointer-events: none;
    opacity: .75;
}
.map-selection-pills .pill-btn.refresh-pill.is-busy svg {
    animation: ssp-spin 900ms linear infinite;
}
@keyframes ssp-spin {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
    .map-selection-pills .pill-btn.refresh-pill.is-busy svg { animation: none; }
}

/* =============================================================================
 * Language picker
 *
 * One control listing the languages by their own names. The pair of TR / EN
 * buttons it replaces made the reader work out which one was current and which
 * was the offer, and it does not scale: a third language would be a third
 * button competing with the map controls for the same corner.
 * ========================================================================== */
.ssp-lang-picker {
    display: inline-flex;
    align-items: center;
    flex: 0 0 auto;
    margin-left: 2px;
}

.ssp-lang-select {
    -webkit-appearance: none;
    appearance: none;
    min-height: 34px;
    padding: 4px 24px 4px 9px;
    border: 1px solid rgba(255, 255, 255, .34);
    border-radius: 9px;
    background-color: rgba(24, 20, 16, .55);
    /* The caret is drawn rather than left to the platform, which would render
       a light system arrow that vanishes on this background. */
    background-image:
        linear-gradient(45deg, transparent 50%, currentColor 50%),
        linear-gradient(135deg, currentColor 50%, transparent 50%);
    background-position: right 11px center, right 6px center;
    background-size: 5px 5px, 5px 5px;
    background-repeat: no-repeat;
    color: #ffb000;
    font-family: 'Inter Tight', system-ui, sans-serif;
    font-size: 12.5px;
    font-weight: 700;
    line-height: 1.2;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.ssp-lang-select:hover { border-color: rgba(255, 255, 255, .6); }
.ssp-lang-select:focus-visible {
    outline: 2px solid #ffb000;
    outline-offset: 2px;
}
/* The list itself is drawn by the platform, so its colours have to be stated
   or the option text is white on white on some builds. */
.ssp-lang-select option {
    background: #1d1a16;
    color: #f4f1ea;
}

body:not(.map-tab-active) .ssp-lang-picker { display: none !important; }

@media (max-width: 430px) {
    .ssp-lang-select { min-height: 32px; font-size: 12px; padding: 3px 22px 3px 8px; }
}

/* =============================================================================
 * Members and activity
 *
 * The audit trail existed in the database from the start and was never shown,
 * so a project manager could invite a crew and then have no way to see who had
 * arrived or what they had done. These are the styles for that view.
 * ========================================================================== */
.ssp-member-facts {
    display: block;
    margin-top: 2px;
    font: 400 12px/1.4 system-ui, sans-serif;
    color: rgba(255, 255, 255, 0.58);
}

.ssp-activity-filter { margin-bottom: 12px; }

.ssp-activity {
    list-style: none;
    margin: 0;
    padding: 0;
    border-top: 1px solid rgba(255, 255, 255, 0.12);
}

.ssp-activity-item {
    display: grid;
    /* Name and time hold their own columns so the eye can run down either one;
       the description takes whatever is left and wraps. */
    grid-template-columns: minmax(90px, 26%) 1fr auto;
    gap: 4px 12px;
    align-items: baseline;
    padding: 9px 2px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.ssp-activity-item[hidden] { display: none; }

.ssp-activity-who {
    font: 600 13px/1.35 system-ui, sans-serif;
    color: #eaf3ec;
    overflow-wrap: anywhere;
}
.ssp-activity-what {
    font: 400 13px/1.35 system-ui, sans-serif;
    color: rgba(255, 255, 255, 0.78);
    overflow-wrap: anywhere;
}
.ssp-activity-when {
    justify-self: end;
    white-space: nowrap;
    font: 500 11.5px/1.35 system-ui, sans-serif;
    color: rgba(255, 255, 255, 0.5);
}

/* On a phone the three columns become two rows: who and when on the first,
   because those are the two that get scanned, and the description under them. */
@media (max-width: 520px) {
    .ssp-activity-item {
        grid-template-columns: 1fr auto;
    }
    .ssp-activity-what {
        grid-column: 1 / -1;
    }
}

/* =============================================================================
 * Saved fields
 *
 * Every completed polygon is its own object, listed here so it can be picked
 * to work on. Before this the application held one ring in one buffer, which
 * is why a second field continued the first one instead of starting clean.
 * ========================================================================== */
.saved-field-list {
    flex: 0 0 100%;
    order: -1;
    margin: 4px 0 8px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    max-height: 168px;
    overflow-y: auto;
}
.saved-field-list .small-text {
    margin: 0;
    color: rgba(255, 255, 255, 0.62);
}

.saved-field {
    display: flex;
    align-items: stretch;
    gap: 4px;
}

.saved-field-pick {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 1px;
    /* A row that is tapped with a thumb while holding an auger. */
    min-height: 44px;
    padding: 6px 10px;
    border: 1px solid rgba(255, 255, 255, 0.18);
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.05);
    color: #f3f6f1;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}
.saved-field-pick strong { font-size: 13px; font-weight: 650; }
.saved-field-pick span { font-size: 11.5px; color: rgba(255, 255, 255, 0.6); }
.saved-field-pick:hover { background: rgba(255, 255, 255, 0.1); }

.saved-field.is-active .saved-field-pick {
    border-color: #ffb000;
    background: rgba(255, 176, 0, 0.14);
}

.saved-field-del {
    flex: 0 0 auto;
    width: 34px;
    min-height: 44px;
    border: 1px solid rgba(255, 255, 255, 0.16);
    border-radius: 8px;
    background: transparent;
    color: rgba(255, 160, 150, 0.9);
    font-size: 18px;
    line-height: 1;
    cursor: pointer;
}
.saved-field-del:hover { background: rgba(180, 60, 50, 0.25); color: #fff; }

/* =============================================================================
 * Map object management
 *
 * One place to see what is drawn on the map and to show or hide any of it.
 * Hiding is a display state: the eye changes what is painted and nothing else,
 * so a hidden field keeps its geometry, its design, its points and its record.
 * ========================================================================== */
.map-layer-manager {
    margin: 6px 0 10px;
    padding: 8px 8px 6px;
    border: 1px solid rgba(255, 255, 255, 0.16);
    border-radius: 10px;
    background: rgba(24, 20, 16, 0.42);
}
.layer-manager-title {
    margin: 0 0 6px;
    font: 600 10.5px/1.3 'Inter Tight', system-ui, sans-serif;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.62);
}
.layer-row {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    /* A row on a phone is hit with a thumb, so the whole row is the target
       rather than the eye alone. */
    min-height: 34px;
    padding: 4px 6px;
    border: 0;
    border-radius: 8px;
    background: transparent;
    color: #ffb000;
    font: 500 12.5px/1.35 'Inter Tight', system-ui, sans-serif;
    text-align: left;
    cursor: pointer;
}
.layer-row:hover { background: rgba(255, 255, 255, 0.07); }
.layer-row.is-off { color: rgba(255, 255, 255, 0.42); }
.layer-eye { display: inline-flex; flex: 0 0 auto; }
.layer-eye svg { width: 18px; height: 18px; display: block; }

.saved-field-eye,
.saved-field-zoom {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 32px;
    min-height: 32px;
    padding: 0;
    border: 0;
    border-radius: 8px;
    background: transparent;
    color: #ffb000;
    font-size: 15px;
    cursor: pointer;
}
.saved-field-eye svg { width: 17px; height: 17px; display: block; }
.saved-field-eye[aria-pressed="false"] { color: rgba(255, 255, 255, 0.42); }
.saved-field-eye:hover,
.saved-field-zoom:hover { background: rgba(255, 255, 255, 0.09); }

/* A hidden field stays in the list, dimmed, because it still exists and the
   point of hiding it is to bring it back. */
.saved-field.is-hidden .saved-field-pick { opacity: 0.5; }

/* The active field indicator. It answers, without being asked, the one
   question that decides where a sampling plan will land. */
.active-field-line {
    margin: 0 0 8px;
    padding: 6px 8px;
    border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, 0.14);
    background: rgba(255, 255, 255, 0.05);
    font: 500 12px/1.4 'Inter Tight', system-ui, sans-serif;
    color: rgba(255, 255, 255, 0.62);
}
.active-field-line.has-field {
    border-color: rgba(255, 176, 0, 0.45);
    background: rgba(255, 176, 0, 0.10);
    color: #ffd479;
}
.active-field-line strong { color: #ffb000; }

/* =============================================================================
 * The map toolbox
 *
 * Three parts: the drawing tools, two collapsible reference sections, and one
 * action bar. The bar is a grid of equal cells rather than a flex row, because
 * equal cells are what make six controls of different natures — two toggles, a
 * select, a section control, a panel control and sign out — read as one
 * toolbar instead of six unrelated things pushed together.
 * ========================================================================== */
.header-map-menu-actions.is-restructured {
    display: block;
    padding: 0;
}

.tb-body { display: block; }
.tb-body[hidden] { display: none; }

.tb-tools {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px;
    padding-bottom: 6px;
}

/* --- collapsible sections ------------------------------------------------ */
.tb-section {
    margin-top: 6px;
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-radius: 10px;
    background: rgba(24, 20, 16, 0.34);
    overflow: hidden;
}

.tb-section-head {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    /* A whole-row target: on a phone this is hit with a thumb, and a chevron
       alone is not a target. */
    min-height: 42px;
    padding: 6px 9px;
    border: 0;
    background: transparent;
    color: #ffb000;
    font: 600 12px/1.35 'Inter Tight', system-ui, sans-serif;
    letter-spacing: 0.03em;
    text-align: left;
    cursor: pointer;
}
.tb-section-head:hover { background: rgba(255, 255, 255, 0.06); }

.tb-section-icon { display: inline-flex; flex: 0 0 auto; }
.tb-section-icon svg { width: 17px; height: 17px; display: block; }
.tb-section-label { flex: 0 0 auto; }

/* The collapsed summary: how many fields there are and which one is active,
   so closing the list does not mean losing sight of what it said. */
.tb-section-note {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    text-align: right;
    font-weight: 500;
    color: rgba(255, 255, 255, 0.55);
}
.tb-section.is-open .tb-section-note { opacity: 0; }

.tb-chevron { display: inline-flex; flex: 0 0 auto; transition: transform 0.18s ease; }
.tb-chevron svg { width: 15px; height: 15px; display: block; }
.tb-section.is-open .tb-chevron { transform: rotate(180deg); }

.tb-section-body { display: none; padding: 0 9px 9px; }
.tb-section.is-open .tb-section-body { display: block; }
/* The two panels already carry their own frame; inside a section they would be
   a box within a box. */
.tb-section-body .map-layer-manager {
    margin: 0;
    padding: 0;
    border: 0;
    background: transparent;
}
.tb-section-body .layer-manager-title { display: none; }

@media (prefers-reduced-motion: reduce) {
    .tb-chevron { transition: none; }
}

/* --- the action bar ------------------------------------------------------ */
.tb-actionbar {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    align-items: center;
    gap: 4px;
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px solid rgba(255, 255, 255, 0.16);
}

.tb-bar-cell {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 0;
}

/* Equal in both directions, and at the size a gloved thumb can hit. The
   toolbar's own buttons carry !important widths from elsewhere, so the size is
   restated here at a specificity that wins. */
.tb-actionbar .tb-bar-cell > .header-layer-action {
    width: 100% !important;
    max-width: 52px !important;
    min-width: 44px !important;
    height: 44px !important;
    min-height: 44px !important;
    border-radius: 10px !important;
}
.tb-actionbar .tb-bar-cell > .header-layer-action:hover {
    background: rgba(255, 255, 255, 0.08) !important;
}
.tb-actionbar .tb-bar-btn svg { width: 21px; height: 21px; display: block; }
.tb-actionbar .tb-bar-btn.is-off { color: rgba(255, 255, 255, 0.45) !important; }

/* The language control is a select, not a button, so it is given the same
   height and corner and allowed to fill its cell. */
.tb-actionbar .ssp-lang-picker { width: 100%; margin: 0; }
.tb-actionbar .ssp-lang-select {
    width: 100%;
    min-height: 44px;
    border-radius: 10px;
    text-align: center;
    text-align-last: center;
}

/* Narrow phones: six cells across 300 px means the language name has to go.
   The control keeps its accessible name and its tooltip, so nothing is lost
   except the width it could not have. */
@media (max-width: 430px) {
    .tb-actionbar {
        gap: 3px;
        /* The language control is a select, not a button, and the one thing it
           must do is show which language is current. Six equal cells on a
           390 px screen truncated "English" to "Engl", so this one cell is
           given the width it needs and the other five stay equal to each
           other. Heights are identical throughout, which is what carries the
           impression of a single toolbar. */
        grid-auto-flow: unset;
        grid-template-columns: 1.5fr repeat(5, 1fr);
    }
    .tb-actionbar .ssp-lang-select {
        padding-left: 5px;
        padding-right: 17px;
        font-size: 11px;
        background-position: right 6px center, right 3px center;
    }
    .tb-section-head { font-size: 11.5px; gap: 6px; padding: 6px 7px; }
}

/* Very narrow: the bar wraps to two rows of three rather than shrinking the
   targets below what a thumb can hit. */
@media (max-width: 340px) {
    /* Two rows of three rather than targets shrunk below what a thumb can hit. */
    .tb-actionbar {
        grid-auto-flow: row;
        grid-template-columns: repeat(3, 1fr);
    }
}

/* The 2D/3D and title controls carry their own sizes from rules with more
   specificity than the bar's, so the bar restates them with more again. Equal
   cells are the whole point of the bar: two buttons a third smaller than their
   neighbours is what made the old row read as unrelated parts. */
body.map-tab-active .tb-actionbar .tb-bar-cell > .header-layer-action,
body.map-tab-active .tb-actionbar .tb-bar-cell > .header-layer-action.mapbox3d-action,
body.map-tab-active .tb-actionbar .tb-bar-cell > .header-layer-action.title-toggle-action,
body.map-tab-active .tb-actionbar .tb-bar-cell > .header-layer-action.header-signout-action {
    width: 100% !important;
    max-width: 54px !important;
    min-width: 44px !important;
    height: 44px !important;
    min-height: 44px !important;
    max-height: 44px !important;
    padding: 0 !important;
    margin: 0 !important;
    border-radius: 10px !important;
    font-size: 20px !important;
    line-height: 1 !important;
}
body.map-tab-active .tb-actionbar .tb-bar-cell > .header-layer-action svg {
    width: 21px !important;
    height: 21px !important;
}

/* =============================================================================
 * Team and progress dashboard
 *
 * A workspace, not a modal: sidebar, header, card grid and a detail drawer that
 * opens beside the grid rather than over it. The layout follows the supplied
 * design; the palette is this application's amber on dark brown rather than the
 * design's green on slate, because the dashboard has to look like part of the
 * product it lives in.
 * ========================================================================== */
.td-root {
    position: fixed;
    inset: 0;
    z-index: var(--z-dashboard);
    display: none;
    background: #16120e;
    color: #f0ece5;
    font-family: 'Inter Tight', system-ui, sans-serif;
}
.td-root.is-open { display: block; }
body.td-open { overflow: hidden; }

.td-shell { display: flex; height: 100%; overflow: hidden; }

/* --- sidebar -------------------------------------------------------------- */
.td-side {
    flex: 0 0 232px;
    display: flex;
    flex-direction: column;
    border-right: 1px solid #2a231c;
    background: #1b1611;
}
.td-brand {
    display: flex; align-items: center; gap: 10px;
    padding: 16px 14px; border-bottom: 1px solid #2a231c;
}
.td-brand-mark {
    width: 26px; height: 26px; border-radius: 7px; flex: 0 0 auto;
    background: rgba(255, 176, 0, 0.14); border: 1px solid #ffb000;
}
.td-brand strong { display: block; font: 700 14px/1.15 'Inter Tight', sans-serif; }
.td-brand span {
    display: block; font: 500 10px/1.4 ui-monospace, monospace;
    letter-spacing: 0.1em; text-transform: uppercase; color: #9b8f80;
}

.td-navlist { flex: 1; overflow: auto; padding: 10px 8px; display: flex; flex-direction: column; gap: 2px; }
.td-nav {
    display: flex; align-items: center; gap: 11px; width: 100%;
    min-height: 42px; padding: 9px 10px;
    border: 0; border-radius: 8px; cursor: pointer;
    background: transparent; color: #b9ad9d; text-align: left;
    font: 500 13.5px/1 'Inter Tight', sans-serif;
}
.td-nav svg { width: 17px; height: 17px; flex: 0 0 auto; }
.td-nav:hover { background: #241d16; color: #f5f1ea; }
.td-nav.is-on {
    background: rgba(255, 176, 0, 0.13);
    color: #ffb000;
    box-shadow: inset 0 0 0 1px rgba(255, 176, 0, 0.32);
}

.td-side-foot { border-top: 1px solid #2a231c; padding: 12px 10px; }
.td-access {
    border: 1px solid #33291f; border-radius: 9px; padding: 10px 11px; background: #211a14;
}
.td-access span {
    display: block; font: 500 10px/1.3 ui-monospace, monospace;
    letter-spacing: 0.11em; text-transform: uppercase; color: #9b8f80;
}
.td-access strong { display: block; margin-top: 5px; font: 600 13px/1 'Inter Tight', sans-serif; color: #ffb000; }

/* --- header --------------------------------------------------------------- */
.td-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.td-head {
    flex: 0 0 auto; display: flex; align-items: center; gap: 12px;
    padding: 12px 16px; border-bottom: 1px solid #2a231c; background: #1b1611;
}
.td-head-title { min-width: 0; flex: 1; }
.td-head-title h1 {
    margin: 0; font: 700 17px/1.15 'Inter Tight', sans-serif; letter-spacing: -0.01em;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.td-head-title p {
    margin: 2px 0 0; font: 400 11.5px/1.4 'Inter Tight', sans-serif; color: #9b8f80;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.td-head-tools { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
.td-search {
    height: 36px; width: 240px; padding: 0 11px;
    border: 1px solid #3a2f24; border-radius: 8px; background: #241d16;
    color: #f0ece5; font: 400 13px/1 'Inter Tight', sans-serif;
}
.td-search:focus { outline: none; border-color: #ffb000; }
.td-btn {
    height: 36px; padding: 0 13px; border-radius: 8px; cursor: pointer;
    border: 1px solid #3a2f24; background: #241d16; color: #e8e0d5;
    font: 600 12.5px/1 'Inter Tight', sans-serif;
}
.td-btn:hover { background: #2e251c; }
.td-btn[disabled] { opacity: 0.6; cursor: default; }
.td-btn.is-accent { border-color: #ffb000; background: rgba(255, 176, 0, 0.13); color: #ffb000; }

/* --- content -------------------------------------------------------------- */
.td-content { flex: 1; min-height: 0; display: flex; }
.td-body { flex: 1; min-width: 0; overflow: auto; padding: 16px; }
.td-loading { padding: 40px; text-align: center; color: #9b8f80; font-size: 13px; }

/* Metric cards. Equal in every dimension: one grid, one card definition, so
   "not recorded" occupies the same box as a three digit number and the row
   does not go ragged. */
/* The summary metrics, in a row that divides evenly.
   auto-fit at a 150px minimum gave whatever number of columns happened to fit,
   so five metrics on a wide screen became four across and one alone on a
   second line. Four to a row above 1100px and two below keeps every row full
   whatever the count, which is what stops the strip looking broken. */
.td-metrics {
    display: grid; gap: 10px; margin-bottom: 14px;
    grid-template-columns: repeat(4, minmax(0, 1fr));
}
@media (max-width: 1100px) {
    .td-metrics { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.td-metric {
    display: flex; flex-direction: column; gap: 7px; min-height: 84px;
    padding: 11px 12px 12px; cursor: pointer; text-align: left;
    border: 1px solid #33291f; border-radius: 10px; background: #221b15;
}
.td-metric:hover { background: #2a2119; border-color: #4a3b2c; }
.td-metric.is-sel { border-color: #ffb000; }
.td-metric-label {
    font: 500 9.5px/1.25 ui-monospace, monospace; letter-spacing: 0.11em;
    text-transform: uppercase; color: #9b8f80;
}
.td-metric-value {
    display: flex; align-items: baseline; gap: 5px;
    font: 700 22px/1 'Inter Tight', sans-serif; margin-top: auto;
}
.td-metric-unit { font: 500 11px/1 'Inter Tight', sans-serif; color: #9b8f80; }
.td-metric-none { font: 500 13px/1.3 'Inter Tight', sans-serif; color: #8a7f71; }
.td-metric-bar { height: 3px; border-radius: 3px; background: #33291f; overflow: hidden; }
.td-metric-bar i { display: block; height: 3px; border-radius: 3px; }

.tone-ok, i.tone-ok { color: #7fc08a; background: #7fc08a; }
.tone-warn, i.tone-warn { color: #e0a33e; background: #e0a33e; }
.tone-info, i.tone-info { color: #78b0d8; background: #78b0d8; }
.tone-muted, i.tone-muted { color: #9b8f80; background: #9b8f80; }
.td-metric-value.tone-ok { background: none; }
.td-metric-value.tone-warn { background: none; }
.td-metric-value.tone-info { background: none; }
.td-metric-value.tone-muted { background: none; }

/* --- cards ---------------------------------------------------------------- */
.td-grid {
    display: grid; gap: 12px; align-items: start;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
}
/* The Overview is two purposeful columns, not a width-driven reflow.
   Each column stacks its own cards, so a long crew list and a short
   Invitations panel no longer sit side by side leaving half a column empty.
   The columns are equal width and independent in height, which is what makes
   the dashboard read as balanced without forcing cards to match. */
.td-grid-overview {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: start;
}
.td-col { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.td-col-full { grid-column: 1 / -1; }

/* One breakpoint, at the width where two columns stop being readable rather
   than at a device size. Below it the columns simply stack, and the reading
   order stays people, then ground. */
@media (max-width: 900px) {
    .td-grid-overview { grid-template-columns: 1fr; }
}

.td-card { background: #221b15; border: 1px solid #33291f; border-radius: 12px; overflow: hidden; }
.td-card.is-wide { grid-column: 1 / -1; }
.td-card-head {
    display: flex; align-items: center; gap: 9px;
    padding: 12px 12px 12px 16px; border-bottom: 1px solid #2c231b;
}
.td-card-head h3 {
    margin: 0; font: 600 11.5px/1.2 'Inter Tight', sans-serif;
    letter-spacing: 0.09em; text-transform: uppercase; color: #d8cfc2;
}
.td-count {
    font: 600 10.5px/1 ui-monospace, monospace; padding: 3px 6px;
    border-radius: 5px; background: #2e251c; color: #b9ad9d;
}
.td-spacer { flex: 1; }
.td-link {
    border: 0; background: transparent; cursor: pointer; color: #ffb000;
    font: 600 11.5px/1 'Inter Tight', sans-serif; padding: 6px 8px; border-radius: 6px;
}
.td-link:hover { background: rgba(255, 176, 0, 0.12); }
.td-caret {
    width: 30px; height: 30px; border-radius: 7px; cursor: pointer;
    border: 1px solid #3a2f24; background: #241d16; color: #b9ad9d;
    display: grid; place-items: center;
}
.td-caret svg { width: 13px; height: 13px; transform: rotate(-90deg); transition: transform 0.18s ease; }
.td-caret.is-open svg { transform: none; }
.td-card-body { padding: 5px 0 7px; }

/* A card whose list is long scrolls inside itself rather than stretching its
   column. Without this the crew card sets the height of everything beside it. */
.td-grid-overview .td-card-body { max-height: 420px; overflow-y: auto; }
.td-grid-overview .td-card-body::-webkit-scrollbar { width: 8px; }
.td-grid-overview .td-card-body::-webkit-scrollbar-thumb {
    background: #3a2f24; border-radius: 4px;
}

/* --- rows ----------------------------------------------------------------- */
.td-row {
    display: grid; grid-template-columns: auto 1fr auto; gap: 3px 10px;
    align-items: center; width: 100%; min-height: 48px; padding: 9px 16px;
    border: 0; border-left: 2px solid transparent; background: transparent;
    color: inherit; text-align: left; cursor: pointer;
}
.td-row:hover { background: #2a2119; }
.td-row.is-sel { border-left-color: #ffb000; background: #2a2119; }
.td-row.is-static { cursor: default; grid-template-columns: 1fr; }
.td-row.is-revoked, .td-row.is-expired { opacity: 0.55; }
.td-avatar {
    width: 28px; height: 28px; border-radius: 8px; display: grid; place-items: center;
    background: rgba(255, 176, 0, 0.14); color: #ffb000;
    font: 600 11px/1 ui-monospace, monospace; flex: 0 0 auto;
}
.td-row-main { min-width: 0; grid-column: 2; }
.td-row-title {
    display: block; font: 500 13.5px/1.3 'Inter Tight', sans-serif; color: #f0ece5;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.td-row-title.mono { font-family: ui-monospace, monospace; }
.td-row-sub {
    display: block; margin-top: 2px; font: 400 11.5px/1.45 'Inter Tight', sans-serif;
    color: #9b8f80; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.td-row-right { font: 600 12.5px/1 ui-monospace, monospace; color: #d8cfc2; white-space: nowrap; }
.td-row-bar {
    grid-column: 1 / -1; height: 4px; border-radius: 3px; background: #33291f;
    margin-top: 6px; overflow: hidden;
}
.td-row-bar i { display: block; height: 4px; border-radius: 3px; background: #7fc08a; }
.td-chip {
    font: 600 10px/1 ui-monospace, monospace; letter-spacing: 0.06em; text-transform: uppercase;
    padding: 4px 7px; border-radius: 5px; background: #2e251c; white-space: nowrap;
}
.td-chip.tone-active { color: #7fc08a; background: rgba(127, 192, 138, 0.14); }
.td-chip.tone-used { color: #78b0d8; background: rgba(120, 176, 216, 0.14); }
.td-chip.tone-expired { color: #9b8f80; }
.td-chip.tone-revoked { color: #e0655c; background: rgba(224, 101, 92, 0.14); }

.td-empty { padding: 26px 16px; text-align: center; }
.td-empty p { margin: 0; font: 500 13px/1.4 'Inter Tight', sans-serif; color: #a19586; }
.td-empty p + p { margin-top: 4px; font-weight: 400; font-size: 11.5px; color: #857a6d; }

/* --- invitations ---------------------------------------------------------- */
.td-chipgrid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; padding: 8px 16px 12px; }
.td-chipstat {
    display: flex; flex-direction: column; gap: 3px; align-items: flex-start;
    padding: 9px 10px; border: 1px solid #33291f; border-radius: 9px;
    background: #241d16; color: inherit; cursor: pointer; min-height: 58px;
}
.td-chipstat:hover { border-color: #4a3b2c; }
.td-chipstat-n { font: 700 18px/1 'Inter Tight', sans-serif; color: #ffb000; }
.td-chipstat-l { font: 500 10px/1.3 ui-monospace, monospace; letter-spacing: 0.08em;
    text-transform: uppercase; color: #9b8f80; }

.td-filters { display: flex; flex-wrap: wrap; gap: 7px; padding: 8px 16px 10px; }
.td-filter {
    cursor: pointer; border: 1px solid #3a2f24; background: #241d16; color: #b9ad9d;
    border-radius: 20px; padding: 7px 13px; min-height: 34px;
    font: 600 12px/1 'Inter Tight', sans-serif;
}
.td-filter.is-on { border-color: #ffb000; background: rgba(255, 176, 0, 0.13); color: #ffb000; }

.td-form { display: grid; gap: 10px; padding: 12px 16px 14px;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); align-items: end; }
.td-form label { display: flex; flex-direction: column; gap: 5px; }
.td-form label span {
    font: 500 10px/1 ui-monospace, monospace; letter-spacing: 0.1em;
    text-transform: uppercase; color: #9b8f80;
}
.td-form select, .td-form input {
    height: 38px; border-radius: 8px; border: 1px solid #3a2f24;
    background: #241d16; color: #f0ece5; padding: 0 10px;
    font: 400 13px/1 'Inter Tight', sans-serif;
}
.td-primary, .td-danger, .td-ghost {
    height: 38px; padding: 0 14px; border-radius: 8px; cursor: pointer;
    font: 600 12.5px/1 'Inter Tight', sans-serif;
}
.td-primary { border: 1px solid #ffb000; background: #ffb000; color: #16120e; }
.td-danger { border: 1px solid rgba(224, 101, 92, 0.5); background: rgba(224, 101, 92, 0.12); color: #e0655c; }
.td-ghost { border: 1px solid #3a2f24; background: #241d16; color: #b9ad9d; width: 100%; margin-top: 10px; }

/* --- drawer --------------------------------------------------------------- */
.td-drawer {
    flex: 0 0 384px; min-width: 0; overflow: auto;
    border-left: 1px solid #2a231c; background: #1b1611;
}
.td-drawer-head {
    display: flex; align-items: flex-start; gap: 10px; padding: 14px 14px 12px 16px;
    border-bottom: 1px solid #2c231b; position: sticky; top: 0; background: #1b1611; z-index: 2;
}
.td-kind {
    font: 500 9.5px/1.3 ui-monospace, monospace; letter-spacing: 0.12em;
    text-transform: uppercase; color: #ffb000;
}
.td-drawer-head h2 { margin: 4px 0 0; font: 700 16px/1.25 'Inter Tight', sans-serif; }
.td-drawer-head p { margin: 2px 0 0; font: 400 11.5px/1.5 'Inter Tight', sans-serif; color: #9b8f80; }
.td-close {
    flex: 0 0 auto; width: 30px; height: 30px; border-radius: 7px; cursor: pointer;
    border: 1px solid #3a2f24; background: #241d16; color: #b9ad9d;
    display: grid; place-items: center;
}
.td-close svg { width: 14px; height: 14px; }
.td-drawer-body { padding: 13px 16px 24px; }

.td-kpis { display: grid; gap: 8px; grid-template-columns: 1fr 1fr; margin-bottom: 14px; }
.td-kpi { border: 1px solid #33291f; border-radius: 9px; background: #221b15; padding: 9px 10px; }
.td-kpi span {
    display: block; font: 500 9.5px/1.25 ui-monospace, monospace;
    letter-spacing: 0.1em; text-transform: uppercase; color: #9b8f80;
}
.td-kpi strong { display: block; margin-top: 5px; font: 700 17px/1.15 'Inter Tight', sans-serif; }
.td-sub {
    font: 600 10.5px/1 'Inter Tight', sans-serif; letter-spacing: 0.1em;
    text-transform: uppercase; color: #a19586; margin: 4px 0 8px;
}
.td-list { border: 1px solid #33291f; border-radius: 10px; background: #221b15; overflow: hidden; }
.td-listrow {
    display: flex; align-items: flex-start; gap: 10px; padding: 9px 12px;
    border-bottom: 1px solid #2c231b;
    font: 400 12px/1.45 'Inter Tight', sans-serif; color: #d8cfc2;
}
.td-listrow:last-child { border-bottom: 0; }
.td-listrow span:first-child { flex: 1; min-width: 0; }
.td-listrow span:last-child { color: #9b8f80; white-space: nowrap; font-family: ui-monospace, monospace; font-size: 11.5px; }
.td-raw {
    display: block; margin-top: 3px; font: 400 10.5px/1.4 ui-monospace, monospace;
    color: #857a6d; font-style: normal;
}
.td-note { font: 400 11.5px/1.6 'Inter Tight', sans-serif; color: #a19586; margin: 0 0 12px; }
.td-actions { display: flex; flex-direction: column; gap: 8px; margin-top: 14px; }
.td-actions button { width: 100%; }

.td-toast {
    position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%);
    display: none; padding: 10px 15px; border-radius: 9px;
    border: 1px solid #4a3b2c; background: #241d16; color: #f0ece5;
    font: 500 12.5px/1 'Inter Tight', sans-serif; box-shadow: 0 12px 30px rgba(0, 0, 0, 0.5);
}
.td-toast.is-on { display: block; }

/* --- tablet: the sidebar keeps its icons and gives up its labels ---------- */
@media (max-width: 1100px) {
    .td-side { flex-basis: 64px; }
    .td-brand div, .td-nav span, .td-side-foot { display: none; }
    .td-nav { justify-content: center; padding: 9px 0; }
    .td-drawer { flex-basis: 320px; }
    .td-search { width: 170px; }
}

/* --- phone: navigation moves to the bottom, the drawer becomes the view --- */
@media (max-width: 760px) {
    .td-shell { flex-direction: column-reverse; }
    .td-side {
        flex: 0 0 auto; flex-direction: row; border-right: 0; border-top: 1px solid #2a231c;
        padding-bottom: env(safe-area-inset-bottom, 0px);
    }
    .td-brand { display: none; }
    .td-navlist { flex-direction: row; overflow-x: auto; padding: 6px; gap: 2px; }
    .td-nav {
        flex: 1 0 auto; min-width: 62px; flex-direction: column; gap: 4px;
        padding: 8px 6px; font-size: 9.5px; text-align: center;
    }
    .td-nav span { display: block; white-space: nowrap; }
    .td-nav svg { width: 19px; height: 19px; }

    .td-head { flex-wrap: wrap; gap: 8px; }
    .td-head-tools { width: 100%; }
    .td-search { flex: 1; width: auto; }
    .td-metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .td-grid { grid-template-columns: 1fr; }
    .td-body { padding: 12px; }
    .td-chipgrid { grid-template-columns: repeat(2, 1fr); }

    /* One thing at a time on a small screen: opening a detail replaces the
       grid rather than squeezing beside it. */
    .td-content:has(.td-drawer) .td-body { display: none; }
    .td-drawer { flex: 1; border-left: 0; }
}

@media (max-width: 400px) {
    .td-metrics { grid-template-columns: 1fr; }
}

/* Search result summary, sync line, and the mobile reflow of the dashboard. */
.td-hits { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
.td-hit {
    font: 500 11.5px/1 'Inter Tight', sans-serif; color: #b9ad9d;
    border: 1px solid #3a2f24; background: #241d16;
    border-radius: 20px; padding: 7px 11px; min-height: 32px;
    display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
}
.td-hit b { color: #ffb000; font-weight: 700; }
.td-hit.is-zero { opacity: 0.45; cursor: default; }
.td-syncline {
    margin: 6px 0 0; width: 100%; text-align: right;
    font: 400 11px/1.4 'Inter Tight', sans-serif; color: #9b8f80;
}

/* --- phone and small tablet ------------------------------------------------
 * Mobile first in behaviour if not in source order: every horizontal
 * arrangement in the dashboard becomes vertical, the metric row drops to two
 * columns and then one, and nothing is allowed to scroll sideways. The three
 * header actions stay reachable by giving them a row of their own rather than
 * by shrinking them.
 * ------------------------------------------------------------------------ */
@media (max-width: 900px) {
    .td-head { flex-wrap: wrap; row-gap: 8px; padding: 10px 12px; }
    .td-head-title { flex: 1 1 100%; }
    .td-head-tools { width: 100%; gap: 6px; }
    .td-search { flex: 1 1 auto; width: auto; min-width: 0; }
    .td-btn { flex: 0 0 auto; padding: 0 11px; font-size: 12px; }

    .td-metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .td-grid { grid-template-columns: 1fr; }
    .td-body { padding: 12px; }

    /* Rows: the count moves under the name instead of fighting it for width,
       which is what stops long names being clipped on a narrow screen. */
    .td-row { grid-template-columns: auto 1fr; row-gap: 2px; }
    .td-row-right { grid-column: 2; justify-self: start; font-size: 12px; }
    .td-row .td-chip { grid-column: 2; justify-self: start; }
    .td-row-title, .td-row-sub { white-space: normal; }

    .td-chipgrid { grid-template-columns: repeat(2, 1fr); }
    .td-form { grid-template-columns: 1fr; }
    .td-kpis { grid-template-columns: 1fr 1fr; }
    .td-listrow { flex-wrap: wrap; row-gap: 2px; }
    .td-listrow span:last-child { text-align: left; }
}

@media (max-width: 560px) {
    .td-head-title h1 { font-size: 15px; }
    .td-head-title p { display: none; }
    .td-btn { height: 40px; }
    .td-search { height: 40px; }
    .td-metric { min-height: 74px; padding: 9px 10px 10px; }
    .td-metric-value { font-size: 19px; }
    .td-card-head { padding: 10px 10px 10px 12px; }
    .td-row { padding: 10px 12px; }
    .td-drawer-body { padding: 12px 12px 22px; }
    .td-nav { min-width: 56px; }
}

@media (max-width: 380px) {
    .td-metrics { grid-template-columns: 1fr; }
    .td-chipgrid { grid-template-columns: 1fr 1fr; }
    .td-kpis { grid-template-columns: 1fr; }
}

/* Nothing in the dashboard may scroll sideways. If a value cannot fit it wraps
   or truncates; it does not push the layout wider than the screen. */
.td-root, .td-shell, .td-main, .td-body, .td-drawer { max-width: 100vw; }
.td-body, .td-drawer { overflow-x: hidden; }
.td-row, .td-listrow, .td-metric { min-width: 0; }
.td-row-main, .td-kpi, .td-listrow span { min-width: 0; overflow-wrap: anywhere; }

/* The bottom navigation fits its six items rather than scrolling. A strip you
   have to swipe to find "Invitations" in is a strip whose last items are never
   used, so the labels shrink and the cells share the width equally instead. */
@media (max-width: 760px) {
    .td-navlist { overflow-x: visible; }
    .td-nav { flex: 1 1 0; min-width: 0; padding: 8px 2px; }
    .td-nav span {
        font-size: 9px; overflow: hidden; text-overflow: ellipsis;
        white-space: nowrap; max-width: 100%;
    }
}
@media (max-width: 360px) {
    .td-nav span { font-size: 8.5px; }
    .td-nav svg { width: 17px; height: 17px; }
}

/* Icon buttons inside the dashboard are 36 px on touch screens. 30 px is a
   comfortable mouse target and a poor thumb one, and these are the controls
   that collapse a card or close the detail view. */
@media (max-width: 900px) {
    .td-caret, .td-close { width: 36px; height: 36px; }
    .td-caret svg, .td-close svg { width: 15px; height: 15px; }
    .td-filter { min-height: 38px; }
    .td-chipstat { min-height: 62px; }
    .td-hit { min-height: 36px; }
}

/* The "All" link in a card header is a real destination, not decoration, so it
   gets a real target on touch screens. */
@media (max-width: 900px) {
    .td-link { min-height: 36px; padding: 6px 10px; }
}

/* --- collected samples ---------------------------------------------------- */
.td-toolbar {
    display: flex; flex-wrap: wrap; align-items: flex-end; gap: 8px;
    padding: 10px 14px 12px; border-bottom: 1px solid #2c231b;
}
.td-viewtabs { display: flex; gap: 4px; }
.td-vtab {
    border: 1px solid #3a2f24; background: #241d16; color: #b9ad9d;
    border-radius: 20px; padding: 8px 14px; min-height: 38px; cursor: pointer;
    font: 600 12px/1 'Inter Tight', sans-serif;
}
.td-vtab.is-on { border-color: #ffb000; background: rgba(255, 176, 0, 0.13); color: #ffb000; }
.td-fsel { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.td-fsel span {
    font: 500 9.5px/1 ui-monospace, monospace; letter-spacing: 0.1em;
    text-transform: uppercase; color: #9b8f80;
}
.td-fsel select, .td-fsel input {
    height: 38px; min-width: 120px; max-width: 190px; padding: 0 8px;
    border: 1px solid #3a2f24; border-radius: 8px; background: #241d16;
    color: #f0ece5; font: 400 12.5px/1 'Inter Tight', sans-serif;
}

.td-columns {
    display: flex; flex-wrap: wrap; gap: 6px 14px;
    padding: 10px 14px; border-bottom: 1px solid #2c231b; background: #1e1811;
}
.td-colopt {
    display: flex; align-items: center; gap: 6px; min-height: 32px;
    font: 400 12px/1 'Inter Tight', sans-serif; color: #d8cfc2; cursor: pointer;
}
.td-colopt input { accent-color: #ffb000; width: 16px; height: 16px; }

/* The table is the one place sideways scrolling is right: a wide record is
   wide, and squeezing twenty columns into a phone would make all of them
   unreadable. It scrolls inside its own box and never widens the page. */
.td-tablewrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.td-table { border-collapse: collapse; width: 100%; min-width: max-content; }
.td-table th, .td-table td {
    padding: 8px 12px; text-align: left; white-space: nowrap;
    border-bottom: 1px solid #2c231b;
    font: 400 12px/1.4 'Inter Tight', sans-serif; color: #d8cfc2;
}
.td-table th { position: sticky; top: 0; background: #241d16; z-index: 1; padding: 0; }
.td-table th button {
    width: 100%; padding: 10px 12px; border: 0; background: transparent; cursor: pointer;
    color: #b9ad9d; text-align: left; white-space: nowrap;
    font: 600 10.5px/1.3 ui-monospace, monospace; letter-spacing: 0.06em; text-transform: uppercase;
}
.td-table th button:hover { color: #ffb000; }
.td-table tbody tr { cursor: pointer; }
.td-table tbody tr:hover td { background: #2a2119; }

.td-group { border-top: 1px solid #2c231b; }
.td-group-head { display: flex; align-items: center; gap: 8px; padding: 0 12px 0 0; }
.td-group-toggle {
    flex: 1; display: flex; flex-direction: column; align-items: flex-start; gap: 3px;
    min-height: 52px; padding: 10px 14px; border: 0; background: transparent;
    color: inherit; text-align: left; cursor: pointer;
}
.td-group-head.is-open { background: #241d16; }
.td-group-name { font: 600 13px/1.3 'Inter Tight', sans-serif; color: #f0ece5; }
.td-group-facts { font: 400 11.5px/1.4 'Inter Tight', sans-serif; color: #9b8f80; }
.td-mini {
    flex: 0 0 auto; min-height: 34px; padding: 0 12px; cursor: pointer;
    border: 1px solid #3a2f24; border-radius: 8px; background: #241d16; color: #b9ad9d;
    font: 600 11.5px/1 'Inter Tight', sans-serif;
}
.td-mini:hover { color: #ffb000; border-color: #ffb000; }

/* --- stage guidance ------------------------------------------------------- */
.td-guide {
    border: 1px solid rgba(255, 176, 0, 0.35); background: rgba(255, 176, 0, 0.07);
    border-radius: 12px; padding: 14px 16px; margin-bottom: 14px;
}
.td-guide h3 { margin: 0; font: 700 15px/1.2 'Inter Tight', sans-serif; color: #ffb000; }
.td-guide p { margin: 5px 0 0; font: 400 12.5px/1.5 'Inter Tight', sans-serif; color: #d8cfc2; }
.td-guide-steps { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 11px; }
.td-guide-step {
    min-height: 38px; padding: 0 14px; cursor: pointer; border-radius: 8px;
    border: 1px solid #ffb000; background: rgba(255, 176, 0, 0.14); color: #ffb000;
    font: 600 12.5px/1 'Inter Tight', sans-serif;
}
.td-guide-step:hover { background: rgba(255, 176, 0, 0.22); }

@media (max-width: 900px) {
    .td-toolbar { padding: 10px 12px; gap: 6px; }
    .td-fsel select, .td-fsel input { min-width: 104px; max-width: none; width: 100%; }
    .td-fsel { flex: 1 1 132px; }
    .td-viewtabs { width: 100%; }
    .td-vtab { flex: 1; }
    .td-toolbar .td-btn { flex: 1 1 auto; min-height: 40px; }
    .td-group-head { flex-wrap: wrap; }
}

/* =============================================================================
 * Toolbox, second pass
 *
 * Twelve controls after the duplicate 3D switch was removed, laid out as two
 * rows of six rather than one row of twelve. Six and six divides evenly, so
 * both rows are full and neither ends in a gap; seven and five would have left
 * two empty cells, which is the thing the arrangement is meant to avoid.
 * ========================================================================== */
.header-map-menu-actions.is-restructured .tb-tools,
.td-none-placeholder { }

body.map-tab-active .header-map-menu-actions.is-restructured .tb-tools {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 4px;
    justify-items: center;
    align-items: center;
    padding-bottom: 8px;
}
body.map-tab-active .tb-tools > .header-layer-action,
body.map-tab-active .tb-tools > button {
    width: 100% !important;
    max-width: 54px !important;
    min-width: 42px !important;
    height: 44px !important;
    min-height: 44px !important;
    border-radius: 10px !important;
    margin: 0 !important;
}
body.map-tab-active .tb-actionbar {
    grid-auto-flow: unset;
    grid-template-columns: repeat(6, 1fr);
}

/* The language control: an icon, and a small menu under it. */
.ssp-lang-picker.is-hidden-picker { display: none !important; }
.tb-langwrap { position: relative; display: flex; justify-content: center; width: 100%; }
.tb-langmenu {
    position: absolute;
    bottom: calc(100% + 6px);
    left: 50%;
    transform: translateX(-50%);
    z-index: 20;
    min-width: 148px;
    padding: 5px;
    border: 1px solid #46503f;
    border-radius: 10px;
    background: #20241f;
    box-shadow: 0 14px 34px rgba(0, 0, 0, 0.55);
}
.tb-langmenu[hidden] { display: none; }
.tb-langopt {
    display: flex; align-items: center; gap: 8px; width: 100%;
    min-height: 40px; padding: 6px 9px;
    border: 0; border-radius: 8px; background: transparent; cursor: pointer;
    color: #e8e0d5; text-align: left;
    font: 500 13px/1 'Inter Tight', system-ui, sans-serif;
}
.tb-langopt:hover { background: rgba(255, 255, 255, 0.08); }
.tb-langopt.is-on { color: #ffb000; }
.tb-langtick { width: 14px; flex: 0 0 auto; color: #ffb000; font-size: 12px; }

/* =============================================================================
 * A slimmer scrollbar for the saved field list
 *
 * The default one is a platform artefact from another decade sitting inside a
 * dark panel. This is the same control, narrower, rounded and in the panel's
 * own colours. Native scrolling and momentum on touch are untouched: only the
 * appearance is changed, never the behaviour.
 * ========================================================================== */
.saved-field-list {
    max-height: 46vh;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    scrollbar-width: thin;
    scrollbar-color: rgba(255, 176, 0, 0.45) transparent;
    padding-right: 2px;
}
.saved-field-list::-webkit-scrollbar { width: 6px; height: 6px; }
.saved-field-list::-webkit-scrollbar-track { background: transparent; }
.saved-field-list::-webkit-scrollbar-thumb {
    background: rgba(255, 176, 0, 0.38);
    border-radius: 999px;
}
.saved-field-list::-webkit-scrollbar-thumb:hover { background: rgba(255, 176, 0, 0.62); }
/* A touch screen has no pointer to hover with and no room to spare, so the
   bar is hidden there and the list is scrolled directly. */
@media (hover: none) {
    .saved-field-list { scrollbar-width: none; }
    .saved-field-list::-webkit-scrollbar { width: 0; height: 0; }
}

@media (max-width: 430px) {
    body.map-tab-active .header-map-menu-actions.is-restructured .tb-tools,
    body.map-tab-active .tb-actionbar { gap: 3px; }
}
@media (max-width: 340px) {
    body.map-tab-active .header-map-menu-actions.is-restructured .tb-tools,
    body.map-tab-active .tb-actionbar { grid-template-columns: repeat(4, 1fr); }
}

/* js/i18n.js appends its select to this container on its own schedule, which
   can be after the panel has been restructured. Hiding it by position rather
   than by a class applied once means it stays hidden however late it arrives. */
.header-map-menu-actions.is-restructured > .ssp-lang-picker,
.header-map-menu-actions.is-restructured .ssp-lang-picker:not(.tb-langwrap) {
    display: none !important;
}

/* The tool row's buttons carry their own sizes from rules more specific than
   the grid's, exactly as the action bar's did. Restated here with the same
   weight so all twelve cells are one height. */
body.map-tab-active .header-map-menu-actions.is-restructured .tb-tools > .header-layer-action,
body.map-tab-active .header-map-menu-actions.is-restructured .tb-tools > button,
body.map-tab-active .header-map-menu-actions.is-restructured .tb-tools > .header-layer-action.polygon-action,
body.map-tab-active .header-map-menu-actions.is-restructured .tb-tools > .header-layer-action.polygon-clear-action,
body.map-tab-active .header-map-menu-actions.is-restructured .tb-tools > .header-layer-action.smart-sampling-action,
body.map-tab-active .header-map-menu-actions.is-restructured .tb-tools > .header-layer-action.polygon-manual-action {
    width: 100% !important;
    max-width: 54px !important;
    min-width: 42px !important;
    height: 44px !important;
    min-height: 44px !important;
    max-height: 44px !important;
    padding: 0 !important;
    margin: 0 !important;
    font-size: 20px !important;
    line-height: 1 !important;
}
body.map-tab-active .header-map-menu-actions.is-restructured .tb-tools > button svg {
    width: 21px !important;
    height: 21px !important;
}

/* The project control came from the bottom map row, where the label under the
   glyph is hidden by a rule scoped to that row. In the action bar it is an icon
   among icons, so the label is hidden here too and the glyph is sized to match
   its neighbours. */
#tbActionBar .map-tool-btn span:not(.tool-ico) { display: none !important; }
#tbActionBar .map-tool-btn .tool-ico {
    font-size: 21px !important;
    line-height: 1 !important;
    margin: 0 !important;
}
#tbActionBar .map-tool-btn .tool-ico svg {
    width: 21px !important;
    height: 21px !important;
}
#tbActionBar .map-tool-btn .tool-state-dot { right: 4px; top: 5px; }

/* The project control in the panel toolbar is an icon, not a card. It arrived
   carrying .btn.secondary, which is a filled button style, and next to five
   flat glyphs a filled pale rectangle reads as a different kind of thing. */
#tbActionBar .map-tool-btn,
#tbActionBar #mapProjectBtn {
    background: transparent !important;
    background-image: none !important;
    border: 0 !important;
    box-shadow: none !important;
    color: #ffb000 !important;
    filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.5));
}
#tbActionBar .map-tool-btn:hover,
#tbActionBar #mapProjectBtn:hover {
    background: rgba(255, 255, 255, 0.08) !important;
    color: #ffc23d !important;
}
#tbActionBar .map-tool-btn:active { transform: none !important; }

/* =============================================================================
 * The project chip and its panel
 *
 * The panel states the project and where the work stands, and offers four
 * icons. Team and synchronisation moved out because the team dashboard already
 * owns them; switching project became one of the icons rather than a button
 * the width of the panel.
 * ========================================================================== */
.ssp-syncpanel-head {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    margin-bottom: 6px;
}
.ssp-syncpanel-head .ssp-syncpanel-project { flex: 1; min-width: 0; margin: 0; }

.ssp-syncpanel-tools { display: flex; gap: 2px; flex: 0 0 auto; }
.ssp-ptool {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* One size for all four, so the row reads as one control group. */
    width: 32px;
    height: 32px;
    padding: 0;
    border: 0;
    border-radius: 8px;
    background: transparent;
    color: rgba(255, 255, 255, 0.72);
    cursor: pointer;
}
.ssp-ptool svg { width: 16px; height: 16px; display: block; }
.ssp-ptool:hover { background: rgba(255, 255, 255, 0.1); color: #ffffff; }
.ssp-ptool.is-on { color: #ffb000; }
.ssp-ptool:focus-visible { outline: 2px solid rgba(255, 255, 255, 0.7); outline-offset: 1px; }

/* The save status is text, not a card. */
.ssp-syncpanel-detail {
    padding: 0;
    border: 0;
    background: transparent;
    font: 400 12px/1.5 'Inter Tight', system-ui, sans-serif;
    color: rgba(255, 255, 255, 0.66);
}
.ssp-syncpanel-detail.is-pending { color: #ffd479; }
.ssp-syncpanel-detail.is-warn { color: #ff9b8f; }

/* --- the compact project picker ------------------------------------------ */
.ssp-picker {
    position: fixed;
    inset: 0;
    z-index: var(--z-overlay);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 18px;
    background: rgba(10, 8, 6, 0.62);
}
.ssp-picker[hidden] { display: none; }

/* The card. Taller on a phone than it was, because the list is the point of
   the panel and it was getting whatever the header and footer left over. */
.ssp-picker-card {
    width: 100%;
    max-width: 420px;
    max-height: min(78vh, 78dvh);
    display: flex;
    flex-direction: column;
    border: 1px solid #3a2f24;
    border-radius: 16px;
    background: #1b1611;
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55);
    overflow: hidden;
}

.ssp-picker-head {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 12px 14px 18px;
    border-bottom: 1px solid #2c231b;
}
.ssp-picker-head h3 {
    flex: 1;
    margin: 0;
    font: 700 15px/1.2 'Inter Tight', system-ui, sans-serif;
    color: #f0ece5;
}
.ssp-picker-tools { display: flex; align-items: center; gap: 4px; }

/* Rows are separated by space and a rule, not by hover alone. With neither,
   two projects with similar names read as one block of text. */
.ssp-picker-list {
    flex: 1;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    padding: 10px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.ssp-picker-line {
    display: flex;
    align-items: stretch;
    gap: 8px;
}
.ssp-picker-line .ssp-picker-row { flex: 1; min-width: 0; }

.ssp-picker-row {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 4px;
    width: 100%;
    min-height: 56px;
    padding: 12px 14px;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 11px;
    background: rgba(255, 255, 255, 0.03);
    color: inherit;
    text-align: left;
    cursor: pointer;
    transition: background .15s ease, border-color .15s ease;
}
.ssp-picker-row:hover { background: #241d16; border-color: rgba(255, 255, 255, 0.18); }
.ssp-picker-row.is-open {
    background: rgba(255, 176, 0, 0.1);
    border-color: rgba(255, 176, 0, 0.42);
}
.ssp-picker-name {
    font: 600 14.5px/1.3 'Inter Tight', system-ui, sans-serif;
    color: #f0ece5;
    overflow-wrap: anywhere;
}
.ssp-picker-row.is-open .ssp-picker-name { color: #ffb000; }
.ssp-picker-role {
    font: 400 11.5px/1.35 'Inter Tight', system-ui, sans-serif;
    letter-spacing: 0.04em;
    color: rgba(255, 255, 255, 0.55);
}

/* The way through to everything else, stated once and kept out of the way. */
.ssp-picker-more {
    min-height: 46px;
    border: 0;
    border-top: 1px solid #2c231b;
    background: transparent;
    color: rgba(255, 255, 255, 0.66);
    cursor: pointer;
    font: 500 13px/1 'Inter Tight', system-ui, sans-serif;
}
.ssp-picker-more:hover { color: #ffb000; background: #241d16; }

/* A phone gets the full width and a sheet that rises from the bottom, which is
   where a thumb already is. The desktop keeps the centred card. */
@media (max-width: 560px) {
    .ssp-picker { padding: 0; align-items: flex-end; }
    .ssp-picker-card {
        max-width: none;
        max-height: min(86vh, 86dvh);
        border-radius: 18px 18px 0 0;
        border-bottom: 0;
        padding-bottom: env(safe-area-inset-bottom);
    }
    .ssp-picker-row { min-height: 60px; }
}

/* =============================================================================
 * The project label
 *
 * It reads; it does not act. Every trace of the button it used to be is taken
 * off: the hover, the pressed state, the caret and the pointer cursor. A block
 * that changes under the cursor and cannot be clicked is worse than one that
 * never moved, so none of it is merely disabled.
 * ========================================================================== */
.ssp-syncbar .ssp-syncchip {
    cursor: default !important;
    background: transparent !important;
    border: 0 !important;
    box-shadow: none !important;
    padding: 4px 2px !important;
    -webkit-tap-highlight-color: transparent;
    text-shadow: 0 1px 4px rgba(0, 0, 0, 0.75), 0 0 12px rgba(0, 0, 0, 0.5);
}
.ssp-syncbar .ssp-syncchip:hover,
.ssp-syncbar .ssp-syncchip:active,
.ssp-syncbar.is-open .ssp-syncchip,
.ssp-syncbar.is-state-offline .ssp-syncchip,
.ssp-syncbar.is-state-error .ssp-syncchip,
.ssp-syncbar.is-state-conflict .ssp-syncchip {
    background: transparent !important;
    border: 0 !important;
    box-shadow: none !important;
    transform: none !important;
}
.ssp-syncbar .ssp-chip-caret { display: none !important; }
.ssp-syncbar .ssp-chip-project {
    color: #ffffff;
    font-weight: 600;
}
.ssp-syncbar .ssp-syncbar-state { color: rgba(255, 255, 255, 0.78); }
/* The state colours stay, because "pending" and "failed" have to read
   differently from "saved"; only the box around them is gone. */
.ssp-syncbar.is-state-offline .ssp-syncbar-state,
.ssp-syncbar.is-state-conflict .ssp-syncbar-state { color: #ffd479; }
.ssp-syncbar.is-state-error .ssp-syncbar-state { color: #ff9b8f; }

/* =============================================================================
 * Two tones, and what they mean
 *
 * The five ordinary tools are amber, the colour every other map control in the
 * application already uses, so they read as one functional group with the rest
 * of the interface rather than as a separate strip.
 *
 * Sign out is the only one that is not amber. It is the single action in the
 * row that ends the session, and the difference in tone is what stops a thumb
 * finding it while reaching for the control beside it. Colour is doing a job
 * here, not decoration, which is why exactly one control has the other tone.
 *
 * No fills and no button backgrounds either way: the row is icons on the map,
 * and a filled rectangle around one of them would read as a different kind of
 * thing again.
 * ========================================================================== */
#tbActionBar .tb-bar-cell > *,
#tbActionBar .header-layer-action,
#tbActionBar .map-tool-btn,
#tbActionBar #mapProjectBtn,
#tbActionBar #tbLangBtn,
#tbActionBar .title-toggle-action,
#tbActionBar #tbContentToggle,
#tbActionBar [onclick*="toggleLayerControl"] {
    color: #ffb000 !important;
    background: transparent !important;
    background-image: none !important;
    border: 0 !important;
    box-shadow: none !important;
    opacity: 1 !important;
    filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.55));
}
#tbActionBar .tb-bar-cell > *:hover,
#tbActionBar .header-layer-action:hover,
#tbActionBar #mapProjectBtn:hover,
#tbActionBar #tbLangBtn:hover,
#tbActionBar .title-toggle-action:hover,
#tbActionBar #tbContentToggle:hover {
    color: #ffc23d !important;
    background: rgba(255, 255, 255, 0.10) !important;
}
#tbActionBar .tb-bar-cell > *:active { transform: none !important; }

/* Sign out: the whitish tone, and it alone. Listed after the group rule and at
   the same weight, so it wins on order rather than on a specificity trick that
   the next edit to the group would quietly undo. */
#tbActionBar .header-signout-action,
#tbActionBar .tb-bar-cell > .header-signout-action {
    color: rgba(255, 255, 255, 0.92) !important;
}
#tbActionBar .header-signout-action:hover,
#tbActionBar .tb-bar-cell > .header-signout-action:hover {
    color: #ffffff !important;
    background: rgba(255, 255, 255, 0.12) !important;
}
#tbActionBar .tb-bar-cell > * svg { stroke: currentColor; }

/* The project picker pill matches the refresh, undo and clear controls beside
   it, which take their colour from the map control set. */
.map-selection-pills .pill-btn.project-pill::before,
.map-selection-pills .pill-btn.project-pill::after {
    content: none !important;
    display: none !important;
}
.map-selection-pills .pill-btn.project-pill {
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    min-width: 44px !important;
    min-height: 44px !important;
}
.map-selection-pills .pill-btn.project-pill svg {
    width: 27px;
    height: 27px;
    display: block;
    stroke: currentColor;
    fill: none;
    filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.52));
}

/* All four controls in this corner are one group and are sized as one. The
   undo and clear pills were 32 px against the refresh control's 44, which is
   below a comfortable touch target and made the new project control look like
   a visitor. The glyphs keep their own sizes; only the boxes are equalised. */
body.map-tab-active .map-selection-pills .pill-btn {
    min-width: 44px !important;
    width: 44px !important;
    height: 44px !important;
    min-height: 44px !important;
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    padding: 0 !important;
}

/* =============================================================================
 * The map header wordmark
 *
 * The sign-in screen's lockup, adapted to a header that is 44 px tall and sits
 * over satellite imagery rather than a darkened photograph. Two things change
 * and nothing else: the size, because the header is short, and the shadow,
 * because white type over bright imagery needs one to hold its edges.
 *
 * The h1's own heading styles are overridden here rather than removed from the
 * blocks above, so the title-visibility control, the responsive header rules
 * and the layout that depends on this element all keep working.
 * ========================================================================== */
.hero-title-wrap h1.hero-wordmark {
    display: flex !important;
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
    margin: 0 !important;
    padding: 0 !important;
    border: 0 !important;
    background: none !important;
    font-size: 0 !important;      /* the wordmark sets its own */
    line-height: 1 !important;
    letter-spacing: normal !important;
    text-transform: none !important;
    white-space: nowrap;
    overflow: visible;
}
.hero-title-wrap .st-logo-word {
    /* Clamped rather than fixed: the header is the one place this lockup has to
       share its row with a control, and a name that pushes the three-dot button
       off the edge is worse than a smaller name. */
    font-size: clamp(17px, 5.4vw, 25px) !important;
    text-shadow: 0 2px 8px rgba(0, 0, 0, 0.75), 0 0 16px rgba(0, 0, 0, 0.45);
}
.hero-title-wrap .st-soil { color: rgba(255, 255, 255, 0.93); }
.hero-title-wrap .st-trace { color: #ffffff; }
.hero-title-wrap .st-logo-rule {
    width: clamp(58px, 17vw, 86px);
    margin: 4px 0 0 !important;
    gap: 2px;
    filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.6));
}
.hero-title-wrap .st-logo-rule i { height: 1.5px; }

@media (max-width: 380px) {
    .hero-title-wrap .st-logo-word { font-size: 17px !important; }
    .hero-title-wrap .st-logo-rule { width: 56px; }
}

/* =============================================================================
 * The toolbox button stays still
 *
 * Nothing in this build animates it, but the rule is stated rather than
 * assumed: an idle control that pulses draws the eye to a place where there is
 * nothing to do, and it costs nothing to make that impossible. Interaction is
 * still allowed to show itself, which is what the second rule is for.
 *
 * The Home control's blink is untouched: it marks an active drawing state,
 * which is a real thing to point at.
 * ========================================================================== */
.hero-menu-btn,
.hero-menu-btn::before,
.hero-menu-btn::after {
    animation: none !important;
    transform: none !important;
}
.hero-menu-btn {
    transition: opacity 0.15s ease, color 0.15s ease !important;
    opacity: 0.92;
}
.hero-menu-btn:hover { opacity: 1; }
.hero-menu-btn:active { opacity: 0.75; }
.hero-menu-btn:focus-visible {
    outline: 2px solid rgba(255, 255, 255, 0.8);
    outline-offset: 3px;
    border-radius: 6px;
}

/* The project control's glyph sits in a .tool-ico span that sets its own white,
   so the colour on the button never reached the strokes. The span and the
   shapes are told directly, which is also what makes the hover follow. */
#tbActionBar #mapProjectBtn .tool-ico,
#tbActionBar .map-tool-btn .tool-ico,
#tbActionBar #mapProjectBtn svg,
#tbActionBar .map-tool-btn svg {
    color: #ffb000 !important;
    stroke: #ffb000 !important;
}
#tbActionBar #mapProjectBtn svg path,
#tbActionBar #mapProjectBtn svg circle,
#tbActionBar .map-tool-btn svg path,
#tbActionBar .map-tool-btn svg circle {
    stroke: #ffb000 !important;
}
#tbActionBar #mapProjectBtn:hover .tool-ico,
#tbActionBar #mapProjectBtn:hover svg,
#tbActionBar #mapProjectBtn:hover svg path,
#tbActionBar #mapProjectBtn:hover svg circle {
    color: #ffc23d !important;
    stroke: #ffc23d !important;
}

/* Sign out is the exception and its glyph is told the same way, so a later
   change to the group rule cannot quietly take it with it. */
#tbActionBar .header-signout-action svg,
#tbActionBar .header-signout-action svg path {
    stroke: rgba(255, 255, 255, 0.92) !important;
}
#tbActionBar .header-signout-action:hover svg,
#tbActionBar .header-signout-action:hover svg path {
    stroke: #ffffff !important;
}

/* =============================================================================
 * The title control does not blink
 *
 * .header-layer-action.is-active carries an infinite blink, and the title
 * control wears is-active whenever the title is showing, so it pulsed for as
 * long as the title was on: a permanent animation marking a normal state.
 *
 * The blink is right for what it was written for, a drawing tool that is armed
 * and waiting for the next tap, because that is a state a person needs pulling
 * back to. "The title is visible" is not. So this one control opts out and says
 * the same thing by standing still and looking different.
 * ========================================================================== */
.title-toggle-action,
.title-toggle-action.is-active,
.title-toggle-action.active,
.title-toggle-action .title-toggle-svg,
.title-toggle-action.is-active .title-toggle-svg,
#tbActionBar .title-toggle-action,
#tbActionBar .title-toggle-action.is-active {
    animation: none !important;
}

/* Two static states. Showing: full strength. Hidden: dimmed, with the glyph's
   own eye already differing between the two. No movement in either. */
.title-toggle-action .title-toggle-svg {
    opacity: 1;
    transform: none !important;
    transition: opacity 0.15s ease;
}
.title-toggle-action.is-active .title-toggle-svg {
    opacity: 1;
    transform: none !important;
}
body.header-title-hidden .title-toggle-action .title-toggle-svg { opacity: 0.55; }
body.header-title-hidden #tbActionBar .title-toggle-action { color: rgba(255, 176, 0, 0.6) !important; }

.title-toggle-action:hover .title-toggle-svg { opacity: 1; }
.title-toggle-action:focus-visible {
    outline: 2px solid rgba(255, 255, 255, 0.8);
    outline-offset: 2px;
    border-radius: 8px;
}

/* The header wordmark is type alone now; the rule element is gone from the
   markup, and this keeps any stray copy from reappearing. */
.hero-title-wrap .st-logo-rule { display: none !important; }
.hero-title-wrap h1.hero-wordmark { align-items: center; justify-content: center; }

/* The representation group editor. */
.td-strata { padding: 12px 16px 16px; display: grid; gap: 10px; }
.td-switch, .td-radio {
    display: flex; align-items: center; gap: 8px; min-height: 36px; cursor: pointer;
    font: 500 12.5px/1.3 'Inter Tight', system-ui, sans-serif; color: #d8cfc2;
}
.td-switch input, .td-radio input { accent-color: #ffb000; width: 17px; height: 17px; }
.td-strata-list { display: grid; gap: 8px; }
.td-strata-row {
    display: grid; gap: 8px; padding: 9px 10px;
    border: 1px solid #33291f; border-radius: 10px; background: #221b15;
}
.td-strata-fields { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.td-strata-fields input {
    min-height: 38px; padding: 0 9px; border: 1px solid #3a2f24; border-radius: 8px;
    background: #241d16; color: #f0ece5; font: 400 12.5px/1 'Inter Tight', sans-serif;
    min-width: 0;
}
.td-strata-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.td-strata-actions .td-radio { margin-right: auto; font-size: 11.5px; }
.td-mini.is-danger { color: #e0655c; border-color: rgba(224, 101, 92, 0.5); }
@media (max-width: 560px) {
    .td-strata-fields { grid-template-columns: 1fr; }
}

/* =============================================================================
 * Working country
 *
 * The opening question, and the way back to it. Full screen on a phone,
 * a card on a desktop, and a list that scrolls with the thumb rather than the
 * page underneath it.
 * ========================================================================== */
.cp-root {
    position: fixed;
    inset: 0;
    z-index: var(--z-overlay);
    display: none;
    align-items: center;
    justify-content: center;
    padding: 16px;
    background: rgba(10, 8, 6, 0.72);
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
}
.cp-root.is-open { display: flex; }

.cp-card {
    width: 100%;
    max-width: 440px;
    max-height: min(84vh, 640px);
    display: flex;
    flex-direction: column;
    padding: 18px 18px 14px;
    border: 1px solid #3a2f24;
    border-radius: 16px;
    background: #1b1611;
    box-shadow: 0 26px 64px rgba(0, 0, 0, 0.6);
    color: #f0ece5;
    font-family: 'Inter Tight', system-ui, sans-serif;
}
.cp-card h2 { margin: 0; font: 700 18px/1.25 'Inter Tight', sans-serif; }
.cp-sub {
    margin: 6px 0 0;
    font: 400 12.5px/1.5 'Inter Tight', sans-serif;
    color: rgba(255, 255, 255, 0.62);
}

/* --- the combobox --------------------------------------------------------- */
.cp-combo { position: relative; margin-top: 14px; }

.cp-toggle {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-height: 50px;
    padding: 0 12px;
    border: 1px solid #3a2f24;
    border-radius: 10px;
    background: #241d16;
    color: #f0ece5;
    cursor: pointer;
    font: 500 15px/1.3 'Inter Tight', system-ui, sans-serif;
    text-align: left;
}
.cp-toggle:hover { border-color: #4a3b2c; }
.cp-toggle[aria-expanded='true'] { border-color: #ffb000; }
.cp-current { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cp-current.is-empty { color: rgba(255, 255, 255, 0.5); }
.cp-caret { flex: 0 0 auto; display: inline-flex; color: rgba(255, 255, 255, 0.6); }
.cp-caret svg { width: 17px; height: 17px; display: block; transition: transform 0.16s ease; }
.cp-toggle[aria-expanded='true'] .cp-caret svg { transform: rotate(180deg); }

/* The panel sits inside the card and shares its height budget, so on a phone
   it can never open past the bottom of the screen. */
.cp-panel {
    display: flex;
    flex-direction: column;
    min-height: 0;
    margin-top: 8px;
    border: 1px solid #3a2f24;
    border-radius: 10px;
    background: #1f1913;
    overflow: hidden;
}
.cp-panel[hidden] { display: none; }

.cp-search {
    margin: 8px 8px 6px;
    height: 46px;
    padding: 0 12px;
    border: 1px solid #3a2f24;
    border-radius: 10px;
    background: #241d16;
    color: #f0ece5;
    /* 16px is a floor: below it mobile Safari zooms the page on focus and the
       card jumps out of the viewport. */
    font: 400 16px/1 'Inter Tight', sans-serif;
}
.cp-search:focus { outline: none; border-color: #ffb000; }

.cp-list {
    flex: 1;
    min-height: 0;
    max-height: min(46vh, 340px);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    scrollbar-width: thin;
    scrollbar-color: rgba(255, 176, 0, 0.45) transparent;
    border-top: 1px solid #2c231b;
}
.cp-list::-webkit-scrollbar { width: 6px; }
.cp-list::-webkit-scrollbar-track { background: transparent; }
.cp-list::-webkit-scrollbar-thumb { background: rgba(255, 176, 0, 0.38); border-radius: 999px; }

.cp-row {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-height: 48px;
    padding: 10px 12px;
    border: 0;
    border-bottom: 1px solid #2c231b;
    background: transparent;
    color: #f0ece5;
    text-align: left;
    cursor: pointer;
    font: 500 14px/1.3 'Inter Tight', sans-serif;
}
.cp-row:last-child { border-bottom: 0; }
.cp-row:hover { background: #241d16; }
/* Keyboard highlight and current selection are shown differently: one is where
   you are, the other is what is already chosen, and conflating them makes the
   list impossible to navigate. */
.cp-row.is-cursor { background: #2c2419; box-shadow: inset 2px 0 0 #ffb000; }
.cp-row.is-current { color: #ffb000; }
.cp-tick { margin-left: auto; color: #ffb000; font-size: 13px; }
.cp-code {
    flex: 0 0 auto;
    min-width: 30px;
    font: 600 11px/1 ui-monospace, monospace;
    color: #ffb000;
}
.cp-empty, .cp-note {
    margin: 8px 2px 0;
    font: 400 12px/1.5 'Inter Tight', sans-serif;
    color: rgba(255, 255, 255, 0.55);
}
.cp-empty { padding: 20px; text-align: center; }

.cp-actions { display: flex; justify-content: flex-end; margin-top: 10px; }
.cp-skip {
    min-height: 42px;
    padding: 0 14px;
    border: 1px solid #3a2f24;
    border-radius: 10px;
    background: transparent;
    color: rgba(255, 255, 255, 0.7);
    cursor: pointer;
    font: 500 13px/1 'Inter Tight', sans-serif;
}
.cp-skip:hover { color: #ffb000; border-color: #ffb000; }

/* On a phone the card is the screen: a 250-row list in a floating box is a
   list nobody scrolls to the end of. */
@media (max-width: 560px) {
    .cp-root { padding: 0; }
    .cp-card {
        max-width: none;
        max-height: none;
        height: 100%;
        border: 0;
        border-radius: 0;
        padding: calc(14px + env(safe-area-inset-top, 0px)) 14px
                 calc(12px + env(safe-area-inset-bottom, 0px));
    }
}

/* While the globe is showing there is nothing to draw on, so the field tools
   step aside rather than sitting over a view of the planet. */
body.country-globe-active .mockup-map-tools,
body.country-globe-active .map-selection-pills,
body.country-globe-active .map-save-fab,
body.country-globe-active .live-location-status { display: none !important; }

/* The working country, in the panel with the other settings. */
.tb-country {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 2px 10px;
    width: 100%;
    margin-top: 6px;
    padding: 9px 11px;
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-radius: 10px;
    background: rgba(24, 20, 16, 0.34);
    color: #f0ece5;
    text-align: left;
    cursor: pointer;
    font-family: 'Inter Tight', system-ui, sans-serif;
}
.tb-country:hover { background: rgba(255, 255, 255, 0.06); }
.tb-country-label {
    grid-column: 1;
    font: 600 9.5px/1.3 ui-monospace, monospace;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.55);
}
.tb-country-value {
    grid-column: 1;
    font: 600 13px/1.3 'Inter Tight', sans-serif;
    color: #ffb000;
    overflow: hidden;
    text-overflow: ellipsis;
}
.tb-country-change {
    grid-column: 2;
    grid-row: 1 / span 2;
    align-self: center;
    font: 600 11.5px/1 'Inter Tight', sans-serif;
    color: rgba(255, 255, 255, 0.7);
}

/* The working-area control matches the four beside it exactly. */
.map-selection-pills .pill-btn.country-pill::before,
.map-selection-pills .pill-btn.country-pill::after {
    content: none !important;
    display: none !important;
}
.map-selection-pills .pill-btn.country-pill svg {
    width: 27px;
    height: 27px;
    display: block;
    stroke: currentColor;
    fill: none;
    filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.52));
}

/* The country field inside the project form. Inline rather than floating, so
   it sits in the form's own flow and the list pushes the form down instead of
   covering the fields underneath it. */
.cp-combo-inline { position: relative; width: 100%; }
.cp-combo-inline .cp-toggle { min-height: 44px; font-size: 14px; }
.cp-combo-inline .cp-list { max-height: min(38vh, 260px); }
.cp-combo-inline.is-invalid .cp-toggle { border-color: #e0655c; }

.ssp-fielderr {
    display: block;
    margin-top: 4px;
    color: #e0655c;
    font: 500 11.5px/1.4 'Inter Tight', system-ui, sans-serif;
}
.ssp-fielderr[hidden] { display: none; }

/* While a project is handed over, the map is covered rather than left showing
   the previous project's fields as they are cleared and the next ones drawn. */
body.ssp-project-loading #map::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 800;
    background: rgba(18, 14, 11, 0.55);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
    pointer-events: none;
}
body.ssp-project-loading .map-selection-pills,
body.ssp-project-loading .mockup-map-tools { opacity: 0.35; pointer-events: none; }

/* The single-point toggle: two static states.
 *
 * Active is the amber the rest of the map controls use; inactive is the same
 * glyph at lower strength. No animation in either, because a control that
 * pulses while there is nothing to do teaches people to stop looking at it. */
#tapModeButton { transition: color 0.15s ease, opacity 0.15s ease; }
#tapModeButton, #tapModeButton * { animation: none !important; }
#tapModeButton:not(.active) { opacity: 0.72; }
#tapModeButton:not(.active) .tool-ico { color: rgba(255, 255, 255, 0.75); }
#tapModeButton.active .tool-ico { color: #ffb000; }

/* =============================================================================
 * The analysis export dialog
 * ========================================================================== */
.ax-root {
    position: fixed; inset: 0; z-index: var(--z-dashboard);
    display: none; align-items: center; justify-content: center; padding: 16px;
    background: rgba(10, 8, 6, 0.7);
}
.ax-root.is-open { display: flex; }
.ax-card {
    width: 100%; max-width: 480px; max-height: min(86vh, 700px);
    display: flex; flex-direction: column;
    border: 1px solid #3a2f24; border-radius: 14px; background: #1b1611;
    color: #f0ece5; font-family: 'Inter Tight', system-ui, sans-serif;
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55);
}
.ax-card h2 { margin: 0; padding: 16px 18px 10px; font: 700 17px/1.25 'Inter Tight', sans-serif; }
.ax-body { flex: 1; overflow-y: auto; padding: 0 18px 8px; -webkit-overflow-scrolling: touch; }
.ax-group { padding: 10px 0 12px; border-top: 1px solid #2c231b; }
.ax-group:first-child { border-top: 0; }
.ax-group h3 {
    margin: 0 0 8px; font: 600 10.5px/1.2 ui-monospace, monospace;
    letter-spacing: 0.1em; text-transform: uppercase; color: #9b8f80;
}
.ax-row {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    min-height: 44px; font: 400 13px/1.35 'Inter Tight', sans-serif;
}
.ax-row select, .ax-row input {
    flex: 0 0 auto; width: 168px; height: 40px; padding: 0 9px;
    border: 1px solid #3a2f24; border-radius: 8px; background: #241d16;
    color: #f0ece5; font: 400 13px/1 'Inter Tight', sans-serif;
}
.ax-check {
    display: flex; align-items: center; gap: 9px; min-height: 42px; cursor: pointer;
    font: 400 13px/1.35 'Inter Tight', sans-serif;
}
.ax-check input { width: 18px; height: 18px; accent-color: #ffb000; }
.ax-note { margin: 8px 0 0; font: 400 11.5px/1.5 'Inter Tight', sans-serif; color: #9b8f80; }
.ax-actions {
    display: flex; gap: 8px; justify-content: flex-end;
    padding: 12px 18px 16px; border-top: 1px solid #2c231b;
}
.ax-primary, .ax-ghost {
    min-height: 44px; padding: 0 16px; border-radius: 9px; cursor: pointer;
    font: 600 13px/1 'Inter Tight', sans-serif;
}
.ax-primary { border: 1px solid #ffb000; background: #ffb000; color: #16120e; }
.ax-ghost { border: 1px solid #3a2f24; background: transparent; color: #b9ad9d; }

@media (max-width: 560px) {
    .ax-root { padding: 0; }
    .ax-card {
        max-width: none; max-height: none; height: 100%;
        border: 0; border-radius: 0;
        padding-top: env(safe-area-inset-top, 0px);
        padding-bottom: env(safe-area-inset-bottom, 0px);
    }
    .ax-row { flex-wrap: wrap; }
    .ax-row select, .ax-row input { width: 100%; }
}

/* The single sample point control: same box as the four beneath it, two static
   states, and no animation in either. */
.map-selection-pills .pill-btn.single-point-pill::before,
.map-selection-pills .pill-btn.single-point-pill::after {
    content: none !important;
    display: none !important;
}
.map-selection-pills .pill-btn.single-point-pill svg {
    width: 27px;
    height: 27px;
    display: block;
    stroke: currentColor;
    filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.52));
}
.map-selection-pills .pill-btn.single-point-pill,
.map-selection-pills .pill-btn.single-point-pill * { animation: none !important; }
.map-selection-pills .pill-btn.single-point-pill:not(.active) { opacity: 0.62; }
.map-selection-pills .pill-btn.single-point-pill:not(.active) svg circle { fill: none; }

/* The export dialog's download buttons stack on a phone rather than crowding
   into a row nobody can hit accurately. */
.ax-downloads {
    display: grid;
    gap: 8px;
    padding: 12px 18px 4px;
    grid-template-columns: 1fr 1fr;
}
.ax-downloads .ax-primary,
.ax-downloads .ax-ghost { width: 100%; min-height: 46px; padding: 0 12px; }
.ax-downloads .ax-primary:first-child,
.ax-downloads .ax-primary:nth-child(2) { grid-column: 1 / -1; }
@media (max-width: 560px) {
    .ax-downloads { grid-template-columns: 1fr; }
}

/* =============================================================================
 * Data archive rows
 *
 * The same shape as the collected-samples rows, so moving between the two does
 * not feel like moving between two applications. One row per record, the code
 * and its facts on the left, the subsample count on the right, and a target
 * that a thumb can hit.
 * ========================================================================== */
.archive-row {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    min-height: 56px;
    padding: 10px 12px;
    border: 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.09);
    border-left: 2px solid transparent;
    background: transparent;
    color: inherit;
    text-align: left;
    cursor: pointer;
    font-family: 'Inter Tight', system-ui, sans-serif;
}
.archive-row:last-child { border-bottom: 0; }
.archive-row:hover { background: rgba(255, 255, 255, 0.05); }
.archive-row.is-active {
    border-left-color: #ffb000;
    background: rgba(255, 176, 0, 0.09);
}
.archive-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.archive-code {
    font: 600 13.5px/1.3 'Inter Tight', sans-serif;
    overflow-wrap: anywhere;
}
.archive-row.is-active .archive-code { color: #ffb000; }
.archive-meta {
    font: 400 11.5px/1.4 'Inter Tight', sans-serif;
    color: rgba(255, 255, 255, 0.58);
    overflow-wrap: anywhere;
}
.archive-count {
    flex: 0 0 auto;
    white-space: nowrap;
    font: 500 11.5px/1 ui-monospace, monospace;
    color: rgba(255, 255, 255, 0.7);
}

/* On a narrow screen the count moves under the code rather than squeezing it. */
@media (max-width: 520px) {
    .archive-row { flex-wrap: wrap; row-gap: 4px; }
    .archive-count { width: 100%; }
}

/* =============================================================================
 * Sampling design: manual and system-guided
 * ========================================================================== */
.sd-modes {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 6px;
    margin-bottom: 12px;
    padding: 4px;
    border: 1px solid #3a2f24;
    border-radius: 11px;
    background: #241d16;
}
.sd-mode {
    min-height: 42px;
    padding: 0 10px;
    border: 0;
    border-radius: 8px;
    background: transparent;
    color: rgba(255, 255, 255, 0.66);
    cursor: pointer;
    font: 600 12.5px/1.25 'Inter Tight', system-ui, sans-serif;
}
.sd-mode.is-on { background: #ffb000; color: #16120e; }

.sd-guided {
    margin-bottom: 14px;
    padding: 12px;
    border: 1px solid #33291f;
    border-radius: 11px;
    background: rgba(255, 176, 0, 0.05);
}
.sd-guided[hidden] { display: none; }
.sd-guided .sd-field { margin-bottom: 8px; }
.sd-check {
    display: flex; align-items: center; gap: 9px; min-height: 40px; cursor: pointer;
    font: 400 12.5px/1.35 'Inter Tight', sans-serif; color: #d8cfc2;
}
.sd-check input { width: 18px; height: 18px; accent-color: #ffb000; }
.sd-guided-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.sd-guided-actions .btn { min-height: 44px; }

.sd-advice:empty { display: none; }
.sd-advice {
    margin-top: 12px;
    padding: 12px;
    border: 1px solid #3a2f24;
    border-radius: 10px;
    background: #1f1913;
    font-family: 'Inter Tight', system-ui, sans-serif;
}
.sd-advice-head {
    display: flex; flex-direction: column; gap: 2px; margin-bottom: 10px;
    padding-bottom: 9px; border-bottom: 1px solid #2c231b;
}
.sd-advice-head span {
    font: 600 10px/1.2 ui-monospace, monospace;
    letter-spacing: 0.1em; text-transform: uppercase; color: #9b8f80;
}
.sd-advice-head strong { font: 700 14px/1.3 'Inter Tight', sans-serif; color: #ffb000; }

/* Two columns of facts on a wide panel, one on a phone. */
.sd-advice-facts {
    display: grid;
    grid-template-columns: auto 1fr auto 1fr;
    gap: 4px 10px;
    margin: 0 0 10px;
    font: 400 12px/1.4 'Inter Tight', sans-serif;
}
.sd-advice-facts dt { color: rgba(255, 255, 255, 0.55); }
.sd-advice-facts dd { margin: 0; color: #f0ece5; font-weight: 600; }
.sd-advice-why, .sd-advice-alt {
    margin: 0 0 8px;
    font: 400 12px/1.5 'Inter Tight', sans-serif;
    color: #d8cfc2;
}
.sd-advice-limits {
    margin: 0; padding-left: 16px;
    font: 400 11.5px/1.5 'Inter Tight', sans-serif;
    color: #9b8f80;
}
.sd-advice-empty {
    margin: 0; font: 400 12.5px/1.5 'Inter Tight', sans-serif; color: #9b8f80;
}

/* A control carrying a recommended value says so, until the person edits it. */
.sd-from-advisor { border-color: rgba(255, 176, 0, 0.55) !important; }

@media (max-width: 560px) {
    .sd-advice-facts { grid-template-columns: auto 1fr; }
    .sd-guided-actions .btn { width: 100%; }
}

/* A sampling point's identifier is never hidden by the zoom rules. It is the
   one piece of text on the map that answers "which point is this", and a
   person placing a sample needs it at the zoom they are working at, not only
   past 19. */
body.field-low-zoom .leaflet-tooltip.sample-point-label,
body.field-detail-zoom .leaflet-tooltip.sample-point-label {
    display: block !important;
    opacity: 1 !important;
}
.leaflet-tooltip.sample-point-label {
    pointer-events: none;
    white-space: nowrap;
}

/* Saved primary samples: two actions above, one across.
   Three buttons of unequal label length in one row leave the widest looking
   like an afterthought. */
.sample-actions {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
    margin-top: 8px;
}
.sample-actions .btn,
.sample-actions button.btn {
    width: 100%;
    height: 44px;
    min-height: 44px;
    margin: 0;
    padding: 0 10px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.sample-actions .sample-actions-wide { grid-column: 1 / -1; }

/* =============================================================================
 * Save sample form: one grid, one rhythm
 *
 * The form grew field by field, so rows were built with whatever wrapper was
 * to hand and no two columns lined up. One grid governs all of it now: every
 * control the same height, every gap the same size, and a column count that
 * drops cleanly rather than leaving a half-empty row.
 * ========================================================================== */
#saveSampleForm .row,
.sample-form .row,
.modal-card .row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 12px;
    align-items: end;
    margin-bottom: 12px;
}
#saveSampleForm .row > div,
.sample-form .row > div,
.modal-card .row > div { min-width: 0; }

#saveSampleForm label,
.sample-form label {
    display: block;
    margin-bottom: 5px;
    font: 600 11px/1.3 ui-monospace, monospace;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #9b8f80;
}
#saveSampleForm input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]),
#saveSampleForm select,
#saveSampleForm textarea,
.sample-form input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]),
.sample-form select,
.sample-form textarea {
    /* One height for every control, so a row of a select and two inputs sits
       on one baseline instead of three. */
    width: 100%;
    min-height: 46px;
    box-sizing: border-box;
    padding: 0 11px;
    /* 16px is a floor: below it mobile Safari zooms the page on focus. */
    font-size: 16px;
}
#saveSampleForm textarea,
.sample-form textarea {
    min-height: 84px;
    padding: 11px;
    line-height: 1.5;
    resize: vertical;
}

@media (max-width: 560px) {
    #saveSampleForm .row,
    .sample-form .row,
    .modal-card .row { grid-template-columns: 1fr; gap: 10px; }
    /* The two-above-one-across shape is kept on a phone rather than collapsed
       to a column: Edit and Map are short labels that fit side by side even at
       320 px, and stacking all three makes the card taller for no gain. */
    .sample-actions { grid-template-columns: 1fr 1fr; gap: 6px; }
    .sample-actions .btn { padding: 0 6px; font-size: 12.5px; }
}

/* Clear field view: the same box as its neighbours, static in both states. */
.map-selection-pills .pill-btn.clearview-pill::before,
.map-selection-pills .pill-btn.clearview-pill::after {
    content: none !important;
    display: none !important;
}
.map-selection-pills .pill-btn.clearview-pill svg {
    width: 27px;
    height: 27px;
    display: block;
    stroke: currentColor;
    fill: none;
    filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.52));
}
.map-selection-pills .pill-btn.clearview-pill,
.map-selection-pills .pill-btn.clearview-pill * { animation: none !important; }

/* =============================================================================
 * Sampling design panel: progressive disclosure
 *
 * Four sections, each showing only what is needed at that step. The science is
 * one click away rather than four paragraphs deep on first open.
 * ========================================================================== */
.sd-fold {
    margin: 10px 0 0;
    border: 1px solid #33291f;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.02);
    overflow: hidden;
}
.sd-fold > summary {
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 44px;
    padding: 0 12px;
    cursor: pointer;
    list-style: none;
    font: 600 12.5px/1.3 'Inter Tight', system-ui, sans-serif;
    color: #d8cfc2;
}
.sd-fold > summary::-webkit-details-marker { display: none; }
.sd-fold > summary::before {
    content: "";
    width: 7px; height: 7px;
    border-right: 2px solid #9b8f80;
    border-bottom: 2px solid #9b8f80;
    transform: rotate(-45deg);
    transition: transform 0.15s ease;
}
.sd-fold[open] > summary::before { transform: rotate(45deg); }
.sd-fold > summary:hover { color: #ffb000; }
.sd-fold-body { padding: 4px 12px 12px; }

.sd-section-title {
    margin: 16px 0 8px;
    font: 600 10.5px/1.2 ui-monospace, monospace;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: #9b8f80;
}

/* The three numbers that decide whether a recommendation is accepted. */
.sd-advice-key {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
    margin: 10px 0;
}
.sd-key {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 8px 10px;
    border: 1px solid #33291f;
    border-radius: 9px;
    background: #241d16;
}
.sd-key span {
    font: 600 9.5px/1.2 ui-monospace, monospace;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: #9b8f80;
}
.sd-key strong { font: 700 15px/1.2 'Inter Tight', sans-serif; color: #ffb000; }

.sd-export-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
    gap: 8px;
}
.sd-export-grid .btn { width: 100%; min-height: 44px; margin: 0; }

.sd-primary-actions { display: flex; gap: 8px; margin-top: 14px; }
.sd-primary-actions .btn { min-height: 46px; }
.sd-primary-actions .btn.primary { flex: 1; }

.sd-gps-small {
    margin-top: 10px;
    font-size: 11px;
    color: #7d7264;
}

/* A field carrying a recommended value, and one the person has changed. */
.sd-user-modified {
    border-color: rgba(120, 190, 255, 0.6) !important;
}

@media (max-width: 560px) {
    .sd-advice-key { grid-template-columns: 1fr; }
    .sd-primary-actions { flex-direction: column; }
    .sd-primary-actions .btn { width: 100%; }
    .sd-export-grid { grid-template-columns: 1fr 1fr; }
}

/* Session refresh, in the slot the automated-design icon vacated. */
.header-layer-action.session-refresh-action svg {
    width: 21px;
    height: 21px;
    display: block;
    stroke: currentColor;
    fill: none;
}

/* The instruction line sits clear of the bottom tool row.
 *
 * It grew when the mode instructions were added ("Click the map to add a
 * primary point and its subsampling locations" is a long sentence), and on a
 * narrow screen it wrapped to three lines and reached the controls beneath it.
 * Two lines, then an ellipsis: the full text is in the tooltip and the
 * sentence reads from its beginning either way. */
@media (max-width: 480px) {
    /* Higher specificity than the several single-class !important rules in
       index.html, which win on document order at equal weight. */
    body.map-tab-active .live-location-status,
    body .live-location-status {
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
        overflow: hidden;
        max-width: calc(100vw - 24px);
        line-height: 1.35;
        /* Above the tool row rather than under it. Both were pinned to the
           bottom of the viewport, so the longer instruction text introduced
           with the sampling modes reached down into the controls. */
        bottom: calc(96px + env(safe-area-inset-bottom, 0px)) !important;
    }
}

/* A recommendation whose inputs have changed says so. */
.sd-stale {
    margin: 0 0 10px;
    padding: 8px 10px;
    border: 1px solid rgba(255, 176, 0, 0.45);
    border-radius: 8px;
    background: rgba(255, 176, 0, 0.08);
    color: #ffd479;
    font: 500 12px/1.45 'Inter Tight', system-ui, sans-serif;
}

/* =============================================================================
 * The toolbox button does not blink
 *
 * A rule in index.html blinks any .map-tool-btn carrying .active, which is how
 * the bottom row marks a selected tool. The toolbox button now takes that class
 * while the panel is open, so it inherited a flash that runs for as long as the
 * panel is in use, which is exactly when a person is trying to read what is
 * inside it.
 *
 * A blink says "look here, something is waiting". An open panel is not waiting
 * for anything: it is already open and visible. Colour is enough to say so, and
 * it says it without pulling the eye back every second.
 *
 * Stated at higher specificity than the rule it overrides, so document order
 * cannot decide the outcome.
 * ========================================================================== */
.mockup-map-tools .map-tool-btn#mapToolboxBtn,
.mockup-map-tools .map-tool-btn#mapToolboxBtn::before,
.mockup-map-tools .map-tool-btn#mapToolboxBtn::after,
.mockup-map-tools .map-tool-btn#mapToolboxBtn *,
.mockup-map-tools .map-tool-btn#mapToolboxBtn.active,
.mockup-map-tools .map-tool-btn#mapToolboxBtn.active *,
.mockup-map-tools .map-tool-btn#mapToolboxBtn.active .tool-ico,
.mockup-map-tools .map-tool-btn#mapToolboxBtn.is-active .tool-ico {
    animation: none !important;
    -webkit-animation: none !important;
    transform: none !important;
    transition: color 0.15s ease, opacity 0.15s ease !important;
}

/* The open state, said once and held. */
.mockup-map-tools .map-tool-btn#mapToolboxBtn.active .tool-ico {
    color: #ffb000 !important;
    opacity: 1 !important;
}

/* =============================================================================
 * Remember me
 *
 * The rule above that rescues the text fields from the host page's generic
 * input styling also strips the appearance from the checkbox, which leaves an
 * invisible transparent square: it toggles, and nothing on screen says so.
 * The input keeps its semantics and its keyboard behaviour and is hidden; the
 * box is drawn here where no other rule can flatten it.
 *
 * The whole label is the target and it is 44 px tall, because a 17-pixel
 * checkbox is not something anyone hits reliably with a thumb.
 * ========================================================================== */
.ssp-auth .ssp-gcheck {
    display: inline-flex;
    align-items: center;
    gap: 11px;
    min-height: 44px;
    padding: 4px 2px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    user-select: none;
    -webkit-user-select: none;
}

/* Hidden, not removed: display:none would take it out of the tab order and
   off the accessibility tree, and the label depends on it for its state. */
.ssp-auth .ssp-gcheck input[type="checkbox"] {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: 0;
    padding: 0;
    opacity: 0;
    pointer-events: none;
}

.ssp-auth .ssp-gcheck .ssp-gcheck-box {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    box-sizing: border-box;
    border: 2px solid rgba(255, 255, 255, 0.72) !important;
    border-radius: 6px !important;
    background: rgba(255, 255, 255, 0.06) !important;
    color: transparent;
    transition: background 0.14s ease, border-color 0.14s ease, color 0.14s ease;
}
.ssp-auth .ssp-gcheck .ssp-gcheck-box svg {
    width: 15px;
    height: 15px;
    display: block;
}

/* Checked: filled amber with a dark tick, which reads at a glance in daylight
   and does not depend on accent-color, unsupported on older iOS. */
.ssp-auth .ssp-gcheck input[type="checkbox"]:checked + .ssp-gcheck-box {
    border-color: #ffb000 !important;
    background: #ffb000 !important;
    color: #16120e;
}
.ssp-auth .ssp-gcheck input[type="checkbox"]:focus-visible + .ssp-gcheck-box {
    outline: 2px solid #ffffff;
    outline-offset: 2px;
}
.ssp-auth .ssp-gcheck:active .ssp-gcheck-box { transform: scale(0.94); }

.ssp-auth .ssp-gcheck-text {
    font-family: inherit;
    font-weight: 400;
    font-size: 13.5px;
    line-height: 1.2;
    color: #ffffff;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
}

/* The delete control, set apart so it is never pressed by accident. */
.td-danger { padding: 12px 16px 16px; display: grid; gap: 10px; }
.td-danger p {
    margin: 0;
    font: 400 12.5px/1.5 'Inter Tight', system-ui, sans-serif;
    color: #d8cfc2;
}
.td-danger .td-note { color: #9b8f80; font-size: 11.5px; }
.td-btn.is-danger {
    justify-self: start;
    min-height: 44px;
    padding: 0 16px;
    border: 1px solid rgba(224, 101, 92, 0.65) !important;
    background: rgba(224, 101, 92, 0.10) !important;
    color: #e0655c !important;
    font-weight: 600;
}
.td-btn.is-danger:hover {
    background: rgba(224, 101, 92, 0.18) !important;
    border-color: #e0655c !important;
}
.td-btn.is-danger:disabled { opacity: 0.5; cursor: progress; }
