{{--
    "We are updating" — one panel, used in both places it can appear.

    It showed up twice with two different faces: the console's own overlay in the
    app's light tokens while the application was still up, and then this, the
    503 page, once the containers went down. Two designs for one event, one
    replacing the other mid-update.

    The styles are inline and self-contained rather than Tailwind classes,
    because the other place this renders is the 503 page — shown while the
    application is mid-deploy or freshly installed, exactly when the Vite
    manifest may not exist. A stylesheet reference there would throw instead of
    rendering the reassurance the visitor came for.

    Prefixed class names: this is injected into the console's own document,
    which has a stylesheet of its own, and `.badge` is not a name to claim
    globally.

    ── On the colours, because they were wrong twice ────────────────────────
    Every value below is a copy of a token from resources/css/portal-tokens.css.
    They were not: the first version used Tailwind's slate ramp (#0f172a,
    #64748b, #e2e8f0), which is blue-tinted, against a product whose neutrals
    are warm. Even in daylight the panel read cooler than everything around it.

    And it carried a `prefers-color-scheme: dark` block, which nothing else in
    this product has. On a phone set to dark mode the update screen — and only
    the update screen — turned dark blue. Reported exactly that way. A dark mode
    for one page is not a dark mode; it is one page that does not match.
--}}
<style>
    /* The fonts, declared here too. The console loads them through Vite, but
       the 503 page has no stylesheet at all — so the maintenance screen was the
       one surface rendering in the system sans while every other page was IBM
       Plex. Same files the placeholder uses; if they are missing the page
       degrades to a system sans and still reads. */
    @font-face{font-family:"Plex Sans";src:url("/fonts/ibm-plex-sans-latin-400-normal.woff2") format("woff2");font-weight:400;font-display:swap}
    @font-face{font-family:"Plex Sans";src:url("/fonts/ibm-plex-sans-latin-500-normal.woff2") format("woff2");font-weight:500;font-display:swap}
    @font-face{font-family:"Plex Sans";src:url("/fonts/ibm-plex-sans-latin-600-normal.woff2") format("woff2");font-weight:600;font-display:swap}
    @font-face{font-family:"Plex Sans";src:url("/fonts/ibm-plex-sans-latin-700-normal.woff2") format("woff2");font-weight:700;font-display:swap}
    @font-face{font-family:"Plex Mono";src:url("/fonts/ibm-plex-mono-latin-400-normal.woff2") format("woff2");font-weight:400;font-display:swap}

    .cpu-wrap {
        /* portal-tokens.css: --bg, --text-strong, --text-muted, --accent,
           --accent-text, --surface, --border, --surface-2 */
        --cpu-bg: #f6f6f8; --cpu-fg: #17171c; --cpu-muted: #6e6e7a;
        --cpu-accent: #f97316; --cpu-accent-ink: #b8500a;
        --cpu-card: #ffffff; --cpu-card-2: #fafafb; --cpu-line: #e9e9ee;
        display: grid; place-items: center; text-align: center;
        padding: 4rem 1.5rem;
        /* Viewport units, not `100%`. A percentage resolves against the
           parent's HEIGHT, and on the 503 page the parent is <body>, whose
           height is auto — so it resolved to zero, the panel was only as tall
           as its text, and the bottom two thirds of the screen stayed the
           browser's default white. dvh so a phone's collapsing address bar does
           not leave a strip either; vh first for anything that lacks it. */
        min-height: 100vh; min-height: 100dvh;
        background: var(--cpu-bg); color: var(--cpu-fg);
        font-family: "IBM Plex Sans", "Plex Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
    }
    .cpu-main { max-width: 34rem; width: 100%; }
    .cpu-brand { display: flex; align-items: center; justify-content: center; gap: 0.625rem; }
    .cpu-mark { width: 2.25rem; height: 2.25rem; flex: none; }
    .cpu-word { font-size: 1.25rem; font-weight: 700; letter-spacing: -0.025em; color: var(--cpu-fg); }
    .cpu-word span { font-weight: 600; color: var(--cpu-muted); }
    .cpu-badge { display: inline-flex; align-items: center; gap: 0.5rem; margin-top: 1.5rem;
                 padding: 0.4rem 0.85rem; border: 1px solid #e8cdb2; border-radius: 9999px;
                 background: #fff3e9; color: var(--cpu-accent-ink);
                 font-family: "IBM Plex Mono", "Plex Mono", ui-monospace, monospace;
                 font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.07em; }
    .cpu-dot { width: 0.375rem; height: 0.375rem; border-radius: 9999px; background: var(--cpu-accent);
               animation: cpu-pulse 2s ease-in-out infinite; }
    @keyframes cpu-pulse { 50% { opacity: 0.3; } }
    @media (prefers-reduced-motion: reduce) { .cpu-dot { animation: none; } }
    .cpu-title { margin: 1.5rem 0 0; font-size: clamp(1.6rem, 4vw, 2.1rem); font-weight: 700;
                 line-height: 1.1; letter-spacing: -0.035em; }
    .cpu-body { margin: 0.9rem auto 0; max-width: 42ch; font-size: 0.95rem; line-height: 1.6;
                color: var(--cpu-muted); }
    .cpu-foot { margin-top: 2.25rem; font-family: "IBM Plex Mono", "Plex Mono", ui-monospace, monospace;
                font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.07em; color: var(--cpu-muted); }
    .cpu-stuck { margin-top: 1.5rem; padding-top: 1.25rem; border-top: 1px solid var(--cpu-line); }
    .cpu-stuck p { margin: 0; font-size: 0.85rem; color: var(--cpu-muted); }
    .cpu-dismiss { margin-top: 0.75rem; padding: 0.5rem 1rem; border: 1px solid var(--cpu-line);
                   border-radius: 0.6rem; background: var(--cpu-card); color: var(--cpu-fg);
                   font: inherit; font-size: 0.85rem; font-weight: 500; cursor: pointer; }
    .cpu-dismiss:hover { background: var(--cpu-card-2); }
    /* The one thing anybody waiting actually needs: proof that something is
       happening. Indeterminate on purpose — a deployment has no honest
       percentage, and a bar that pretends to know one always stalls at 90 %.

       Pure CSS: this page is served while the application is down, so nothing
       here may depend on JavaScript having loaded or on the server answering
       another request. */
    .cpu-bar { margin: 2rem auto 0; max-width: 22rem; height: 4px; overflow: hidden;
               border-radius: 999px; background: var(--cpu-card-2); }
    .cpu-bar span { display: block; width: 40%; height: 100%; border-radius: 999px;
                    background: var(--cpu-accent); animation: cpu-slide 1.6s ease-in-out infinite; }
    @keyframes cpu-slide { 0% { transform: translateX(-110%); } 100% { transform: translateX(310%); } }
    /* Somebody who has switched motion off gets a steady bar rather than none:
       the point is to show the page is alive, and a still bar still says that
       more than an empty gap does. */
    @media (prefers-reduced-motion: reduce) {
        .cpu-bar span { width: 100%; animation: none; opacity: 0.6; }
    }
    .cpu-detail { margin-top: 1.1rem; }
    .cpu-step { margin: 0; font-size: 0.82rem; color: var(--cpu-muted); }
</style>

<div class="cpu-wrap">
    <main class="cpu-main">
        {{-- The real mark, not a rounded orange tile. An empty brand square
             reads as an image that failed to load, and this panel is shown at
             the one moment somebody is already wondering whether something is
             broken. --}}
        <div class="cpu-brand"><svg class="cpu-mark" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
            <defs>
                <linearGradient id="cpu-mark-grad" x1="0" y1="0" x2="64" y2="64" gradientUnits="userSpaceOnUse">
                    <stop stop-color="#FB923C"/><stop offset="0.55" stop-color="#F97316"/><stop offset="1" stop-color="#C2560A"/>
                </linearGradient>
            </defs>
            <rect width="64" height="64" rx="15" fill="url(#cpu-mark-grad)"/>
            <path d="M22 41h20a8 8 0 0 0 .7-15.97A11 11 0 0 0 21.4 27.2 8.5 8.5 0 0 0 22 44z" fill="#ffffff" fill-opacity="0.22"/>
            <path d="M32 17 44 44l-12-6-12 6z" fill="#ffffff"/>
        </svg>
            <span class="cpu-word">CluPilot <span>Cloud</span></span>
        </div>

        <div class="cpu-badge"><span class="cpu-dot"></span>{{ __('updating.badge') }}</div>
        <h1 class="cpu-title">{{ __('updating.title') }}</h1>
        <p class="cpu-body">{{ $body ?? __('updating.body') }}</p>

        {{-- Proof of life, for everybody. Whoever is looking at this — a
             customer or the operator who pressed the button — wants one thing
             answered: is anything happening, or am I staring at a dead page.
             This says yes without asking them to read anything. --}}
        <div class="cpu-bar" aria-hidden="true"><span></span></div>

        {{-- The current step, in the console only, as one quiet line.
             It used to be a card with the step in it, a "läuft seit …" line and
             the deployment's raw output underneath — rsync listing every font
             file it copied. None of that is anybody's question while they wait:
             the file list is noise, and the placeholder card ("Wird jetzt
             gestartet.") was a box drawn around the absence of information.
             What is left is what an operator can act on: which step, so a run
             that stops on one is visible without a shell. --}}
        @if ($detail ?? false)
            <div class="cpu-detail">
                <p class="cpu-step" x-show="step" x-text="step" x-cloak></p>
            </div>
        @endif
        <p class="cpu-foot">{{ __('updating.auto') }}</p>

        {{-- Only when the server has stopped answering for long enough that
             this is no longer a restart. An always-present close button would
             be a lie — the deployment does not stop because somebody dismissed
             a panel — but being held behind one while the application is broken
             is worse. --}}
        @if ($detail ?? false)
            <div class="cpu-stuck" x-show="stuck" x-cloak>
                <p>{{ __('updating.stuck') }}</p>
                <button type="button" class="cpu-dismiss" @click="dismiss()">{{ __('updating.dismiss') }}</button>
            </div>
        @endif
    </main>
</div>
