/* WookiVerse Status.
   Chrome copied from the app itself (MainLayout.razor.css): a #f7f7f7 top bar with a #d6d5d5
   hairline, and #111/#222 as the dark brand tone from the docked sidebar. The navy-to-purple
   gradient belongs to the sign-in screen and is deliberately absent here.
   States are Bootstrap semantics and nothing else uses colour.
   Type: Tilt Neon and Fira Code are both already in the app's font import. */

@import url('https://fonts.googleapis.com/css2?family=Tilt+Neon&family=Fira+Code:wght@400;500&display=swap');

:root {
    /* App chrome */
    --bar: #f7f7f7;
    --bar-line: #d6d5d5;
    --dark: #212529;
    --darker: #111;

    /* Bootstrap semantics — states only */
    --success: #198754;
    --warning: #ffc107;
    --danger: #dc3545;
    --secondary: #6c757d;

    --page: #eeeeee;
    --surface: #ffffff;
    --border: #dee2e6;
    --ink: #212529;
    --ink-soft: #6c757d;
    --track: #e9ecef;

    --radius: 6px;
    --mono: 'Fira Code', ui-monospace, SFMono-Regular, Menlo, monospace;
    --display: 'Tilt Neon', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

* { box-sizing: border-box; }

body {
    margin: 0;
    background: var(--page);
    color: var(--ink);
    font-family: var(--display);
    font-size: 15px;
    line-height: 1.55;
}

/* --- Top bar: the app's brand header ------------------------------------------------------
   The app's brand block (NavMenu.razor) is white-on-dark: the sidebar's #111-to-#222 gradient
   under a rgba(0,0,0,.4) tint, carrying the blinking-eyes logo and Wooki<b>Verse</b>. Its
   #f7f7f7 .top-row only reads as chrome because that dark sidebar sits beside it; on a page
   with no sidebar the same grey is invisible. So the brand header IS the top bar here. */

.top-row {
    background-color: var(--darker);
    background-image:
        linear-gradient(rgba(0, 0, 0, .4), rgba(0, 0, 0, .4)),
        linear-gradient(180deg, #111 0%, #222 75%);
    color: #fff;
    height: 3.5rem;
    position: sticky;
    top: 0;
    z-index: 6;
}

.top-row-inner {
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.brand { display: flex; align-items: center; gap: 10px; text-decoration: none; color: #fff; }
.brand img { width: 40px; height: auto; }

.wordmark { font-size: 20px; line-height: 1; }
.wordmark b { font-weight: 400; }

/* Burger — <details> so the menu needs no JavaScript */
.menu { position: relative; }

.menu summary {
    list-style: none;
    cursor: pointer;
    color: #fff;
    padding: 6px 4px 2px;
    border-radius: var(--radius);
}

.menu summary::-webkit-details-marker { display: none; }
.menu summary:hover { color: #c9c7d4; }

.menu ul {
    position: absolute;
    right: 0;
    top: calc(100% + 8px);
    min-width: 220px;
    margin: 0;
    padding: 6px 0;
    list-style: none;
    background: #fff;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: 0 6px 20px rgba(0, 0, 0, .1);
    z-index: 7;
}

.menu a { display: block; padding: 9px 18px; color: var(--ink); text-decoration: none; font-size: 14px; }
.menu a:hover, .menu a:focus-visible { background: var(--secondary); color: #fff; }
.menu a[aria-current="page"] { font-weight: 500; }
.menu .sep { border-top: 1px solid var(--border); margin-top: 6px; padding-top: 6px; }
.menu .sep a { color: var(--ink-soft); font-family: var(--mono); font-size: 12px; }

.container { width: 100%; margin: 0 auto; padding-left: 2rem; padding-right: 1.5rem; }
@media (min-width: 576px)  { .container { max-width: 540px; } }
@media (min-width: 768px)  { .container { max-width: 720px; } }
@media (min-width: 992px)  { .container { max-width: 960px; } }
@media (min-width: 1200px) { .container { max-width: 1140px; } }

.page { padding-top: 30px; padding-bottom: 64px; }

/* --- Banner ------------------------------------------------------------------------------ */

.banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 12px 18px;
    /* Bootstrap mb-3. The stamp used to carry this gap; it moved into the banner. */
    margin-bottom: 1rem;
    padding: 15px 20px;
    border-radius: var(--radius);
    color: #fff;
}

.banner-main { display: flex; flex-direction: column; gap: 3px; }
.banner-text { font-size: 21px; line-height: 1.25; }

/* The stamp lives in the banner now: the state and how fresh it is are one claim, and
   splitting them let a reader take the state on trust without seeing its age. */
.banner-stamp { font-family: var(--mono); font-size: 11px; opacity: .82; }

.banner-affected { display: flex; flex-wrap: wrap; gap: 6px; }
.banner-badge img { width: 22px; height: 22px; object-fit: contain; }

/* Translucent white rather than a semantic colour — a red badge on a red banner disappears. */
.banner-badge {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: .3em .75em .3em .45em;
    border-radius: .375rem;
    background: rgba(255, 255, 255, .22);
    font-size: 12px;
    font-weight: 500;
    line-height: 1.2;
    white-space: nowrap;
}

.banner.up { background: var(--success); }
.banner.down { background: var(--danger); }
/* Amber, not red: something is broken, but not most of it. Sharing red with a major outage
   would leave the page no way to say the difference. */
.banner.partial { background: var(--warning); color: var(--dark); }
.banner.partial .banner-badge { background: rgba(0, 0, 0, .12); color: var(--dark); }
.banner.maintenance { background: var(--secondary); }
.banner.unknown { background: var(--secondary); }

/* Still used by the incidents and uptime pages. */
.stamp { color: var(--ink-soft); font-family: var(--mono); font-size: 12px; margin: 12px 0 28px; }

/* --- Components -------------------------------------------------------------------------- */

.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 16px 18px;
}

/* Two up on desktop — Bootstrap's col-6. The strips still give each day about 7px at the xxl
   container, which is what Statuspage runs at full width. */
/* The platform-wide strip: full width above the per-component grid, so the first thing under
   the banner is one line about the whole estate rather than twelve about its parts. */
.overall { margin-bottom: 10px; overflow: visible; }
.overall .bars { height: 40px; }
.overall .bar { border-right-width: 2px; }

.components { display: grid; grid-template-columns: 1fr; gap: 10px; }
@media (min-width: 992px) { .components { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.component { overflow: visible; }
/* 40px square, matching the module icons in the app nav — not circles: these are pictograms,
   not avatars, and cropping them to a circle clips the artwork. */
.component-icon { width: 40px; height: 40px; object-fit: contain; }
.name { display: flex; align-items: center; gap: 9px; font-weight: 500; }

.component-head {
    display: flex;
    justify-content: space-between;
    /* Centred, not baseline: the 40px icon makes the name side tall, and a baseline-aligned
       badge hangs at the bottom of it. */
    align-items: center;
    gap: 12px;
    margin-bottom: 12px;
}


/* Bootstrap badges. Solid fill for a state we are asserting; a quiet outline for Unknown,
   because "we cannot see" is not a claim about the service and should not shout like one. */
.state {
    display: inline-block;
    padding: .35em .7em;
    font-size: 12px;
    font-weight: 500;
    line-height: 1.2;
    border-radius: .375rem;
    white-space: nowrap;
    color: #fff;
}

.state.up { background: var(--success); }
.state.down { background: var(--danger); }
.state.maintenance { background: var(--secondary); }
.state.degraded { background: var(--warning); color: #000; }
.state.unknown { background: transparent; color: var(--ink-soft); box-shadow: inset 0 0 0 1px var(--border); }

.bars { display: flex; gap: 0; height: 32px; }

/* A popover, not a tooltip: a real element carrying a badge and figures, rather than the
   browser's title attribute, which is one string, slow to appear and unstyleable.
   Deliberately not focusable — 90 bars across 12 components would be 1,080 tab stops, and the
   same figures are in the legend below and day-by-day on the Uptime page. */
.bar { position: relative; }

.pop {
    display: none;
    position: absolute;
    bottom: calc(100% + 10px);
    left: 50%;
    transform: translateX(-50%);
    z-index: 8;
    min-width: 320px;
    padding: 0;
    background: var(--surface);
    color: var(--ink);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: 0 8px 24px rgba(0, 0, 0, .16);
    text-align: left;
    font-size: 12px;
    line-height: 1.45;
    cursor: default;
}

/* Popovers at either end would overflow the panel, so the outermost bars anchor to their own
   edge instead of centring. Driven by index at render time, so nothing has to be measured. */
.bar.pop-start .pop { left: 0; transform: none; }
.bar.pop-end .pop { left: auto; right: 0; transform: none; }

/* Two triangles: the border colour behind, the surface in front, so the arrow keeps the
   popover's outline instead of showing a seam where it meets the card. */
.pop::before, .pop::after {
    content: "";
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    border: 7px solid transparent;
}

.pop::before { top: 100%; border-top-color: var(--border); }
.pop::after { top: calc(100% - 1px); border-top-color: var(--surface); }

.pop-start .pop::before, .pop-start .pop::after { left: 16px; transform: none; }
.pop-end .pop::before, .pop-end .pop::after { left: auto; right: 16px; transform: none; }

/* The title names which component the day belongs to — on a page of twelve strips, the row a
   popover came from stops being obvious the moment the pointer leaves it. */
/* Rows, not a stack: the day, what happened and how long it lasted belong on one line, and the
   platform strip then adds a line per component underneath in the same three columns. */
.pop-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 7px 13px;
}

.pop-row + .pop-row { border-top: 1px solid var(--border); }
.pop-head { background: var(--bar); border-radius: var(--radius) var(--radius) 0 0; }
.pop-head { font-size: 13px; font-weight: 500; }
.pop-day { flex: 1; }
.pop-pct { font-family: var(--mono); font-size: 12px; font-weight: 400; color: var(--ink-soft); }

/* A component's own rows: the window stacked on the left, what it was on the right. */
.pop-window {
    flex: none;
    font-family: var(--mono);
    font-size: 11px;
    line-height: 1.35;
    color: var(--ink-soft);
    white-space: nowrap;
}

.pop-window b { display: block; font-size: 12px; font-weight: 500; color: var(--ink); }
.pop-what { margin-left: auto; text-align: right; font-size: 12px; }

/* Two lines: who and what above, when and how long below. */
.pop-stack { display: block; }
.pop-top { display: flex; align-items: center; gap: 9px; }
.pop-name { flex: 1; font-size: 13px; }
.pop-sub {
    display: block;
    margin-top: 4px;
    padding-left: 29px;
    font-family: var(--mono);
    font-size: 11px;
    color: var(--ink-soft);
}
.pop-when {
    display: flex;
    align-items: center;
    gap: 7px;
    flex: 1;
    font-family: var(--mono);
    font-size: 12px;
    white-space: nowrap;
}

.pop-icon { width: 20px; height: 20px; object-fit: contain; flex: none; }
.pop-len { margin-left: auto; font-family: var(--mono); font-size: 11px; color: var(--ink-soft); white-space: nowrap; }

.pop-figure { font-family: var(--mono); }
.pop-note { color: var(--ink-soft); font-size: 12px; }
.pop .state { flex: none; }

.bar.has-pop:hover { box-shadow: inset 0 0 0 999px rgba(0, 0, 0, .18); }
.bar.has-pop:hover .pop { display: block; }

/* The popover escapes its row, so nothing on the path may clip it. */
.component, .bars { overflow: visible; }
.bar {
    flex: 1 1 0;
    min-width: 0;
    box-sizing: border-box;
    border-right: 1px solid var(--surface);
    background: var(--track);
    background-clip: padding-box;
}

.bar:last-child { border-right: 0; }
.bar.up { background: var(--success); }
.bar.down { background: var(--danger); }
.bar.maintenance { background: var(--secondary); }
.bar.unknown { background: var(--track); }

.legend {
    display: flex;
    justify-content: space-between;
    margin-top: 9px;
    color: var(--ink-soft);
    font-family: var(--mono);
    font-size: 11px;
}

/* --- Incidents --------------------------------------------------------------------------- */

h2 {
    font-size: 21px;
    font-weight: 400;
    margin: 30px 0 10px;
}

h2:first-child { margin-top: 0; }

.open { margin-bottom: 22px; }

/* An open incident on the summary. Coloured down the leading edge by severity so it reads as
   the live thing on the page, without competing with the banner above it. */
.live-incident {
    margin-bottom: 10px;
    border-left: 3px solid var(--secondary);
}

.live-incident.down { border-left-color: var(--danger); }
.live-incident.maintenance { border-left-color: var(--secondary); }

.live-incident h3 { margin: 0 0 6px; font-size: 17px; font-weight: 500; }
.live-incident h3 a { color: var(--ink); text-decoration: none; }
.live-incident h3 a:hover { text-decoration: underline; }

.live-latest { margin: 0 0 6px; font-size: 14px; max-width: 80ch; }
.live-latest b { color: var(--dark); }

.live-when { margin: 0; font-family: var(--mono); font-size: 11px; color: var(--ink-soft); }
.live-when a { color: var(--ink-soft); }

.incident { margin-bottom: 12px; }
.incident h3 { font-size: 19px; font-weight: 500; margin: 0 0 3px; max-width: 60ch; color: var(--ink); }

.incident-when { margin: 0; color: var(--ink-soft); font-family: var(--mono); font-size: 11px; }

/* Chips ride the title row rather than sitting under it: they answer "what does this touch",
   which belongs beside the headline, not stacked between it and the story. */
.incident-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 8px 16px;
    margin-bottom: 14px;
}

/* The order of an incident's updates IS the information, so the shape carries it: one rail
   down the side, a dot per update, newest at the top. */
.timeline { position: relative; margin: 0; padding: 2px 0 0 24px; list-style: none; }

.timeline::before {
    content: "";
    position: absolute;
    left: 5px;
    top: 8px;
    bottom: 8px;
    width: 2px;
    background: var(--border);
}

.update { position: relative; margin: 0 0 14px; font-size: 14px; max-width: 72ch; }
.update:last-child { margin-bottom: 2px; }

.update .dot {
    position: absolute;
    left: -24px;
    top: 6px;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: var(--surface);
    box-shadow: inset 0 0 0 2px var(--secondary);
}

/* The dot's colour is the update's own state, so the rail reads as a progression: red while it
   is being worked out, amber once a fix is being watched, green when it is done. */
.update.bad .dot { background: var(--danger); box-shadow: inset 0 0 0 2px var(--danger); }
.update.watching .dot { background: var(--warning); box-shadow: inset 0 0 0 2px var(--warning); }
.update.good .dot { background: var(--success); box-shadow: inset 0 0 0 2px var(--success); }
.update.neutral .dot { background: var(--secondary); box-shadow: inset 0 0 0 2px var(--secondary); }

.chips { display: flex; flex-wrap: wrap; gap: 6px; margin-left: auto; }

.chip {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    background: var(--secondary);
    border: 1px solid var(--secondary);
    border-radius: .375rem;
    padding: 6px 14px 6px 8px;
    font-size: 13px;
    color: #fff;
}

/* 24px, not the nav's 40px: the app uses 40 for icons in LIST ROWS, and a 40px icon inside an
   inline pill makes a 46px chip that outweighs the incident title it sits beside. */
.chip img { width: 24px; height: 24px; object-fit: contain; }

.update { margin: 8px 0; font-size: 14px; max-width: 72ch; }
.update b { color: var(--dark); }
.update time { border-bottom: 1px dotted var(--border); cursor: help; }
.update .at { display: block; margin-top: 3px; color: var(--ink-soft); font-family: var(--mono); font-size: 11px; }

/* --- Uptime calendar --------------------------------------------------------------------- */

.picker {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    margin-bottom: 20px;
}

.picker-desc { margin: 0; max-width: 60ch; color: var(--ink-soft); font-size: 13px; }
.picker-controls { display: flex; gap: 8px; margin-left: auto; }

.dropdown { position: relative; }

.dropdown .btn {
    display: inline-flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    min-width: 190px;
    padding: 8px 13px;
    font: inherit;
    font-size: 14px;
    background: var(--surface);
    color: var(--ink);
    border: 1px solid #ced4da;
    border-radius: var(--radius);
    cursor: pointer;
    list-style: none;
}

.dropdown .btn::-webkit-details-marker { display: none; }
.dropdown[open] .btn { border-color: var(--ink-soft); }
.dropdown .caret { flex: none; opacity: .7; }

.dropdown .btn > span { flex: 1; text-align: left; }

.dropdown-menu {
    position: absolute;
    right: 0;
    top: calc(100% + 5px);
    z-index: 9;
    min-width: 100%;
    max-height: 340px;
    overflow-y: auto;
    margin: 0;
    padding: 6px 0;
    list-style: none;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: 0 6px 20px rgba(0, 0, 0, .12);
}

.dropdown-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 16px;
    color: var(--ink);
    text-decoration: none;
    font-size: 14px;
    white-space: nowrap;
}

.dropdown-icon { width: 24px; height: 24px; object-fit: contain; flex: none; }

.dropdown-item:hover, .dropdown-item:focus-visible { background: var(--secondary); color: #fff; }
.dropdown-item.active { font-weight: 500; background: var(--bar); }
.dropdown-item.active:hover { background: var(--secondary); color: #fff; }

.months { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 14px; }
.month { overflow: visible; }

.month h3 { display: flex; justify-content: space-between; align-items: baseline; font-size: 15px; font-weight: 500; margin: 0 0 12px; }
.month h3 span { color: var(--ink-soft); font-family: var(--mono); font-size: 12px; font-weight: 400; }

.weekdays {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 3px;
    margin-bottom: 4px;
    color: var(--ink-soft);
    font-size: 11px;
    text-align: center;
}

.weekdays .weekend { color: #a9a9a9; }

.cells { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; overflow: visible; }

.cell {
    position: relative;
    aspect-ratio: 1;
    border-radius: 3px;
    background: var(--track);
    display: flex;
    align-items: center;
    justify-content: center;
}

.cell-num { font-size: 11px; font-family: var(--mono); color: rgba(255, 255, 255, .92); }
.cell.unknown .cell-num { color: var(--ink-soft); }
.cell.blank { background: none; }
.cell.blank .cell-num { display: none; }

.cell.has-pop:hover .pop { display: block; }
.cell.has-pop:hover { box-shadow: inset 0 0 0 999px rgba(0, 0, 0, .18); }
.month { overflow: visible; }
.cell.up { background: var(--success); }
.cell.down { background: var(--danger); }
.cell.maintenance { background: var(--secondary); }

/* Announced, not yet happened. A lighter grey than maintenance itself, because a plan and a
   measurement should not look identical — one of them can still be cancelled. */
.cell.planned { background: #adb5bd; }
.cell.unknown { background: var(--track); }
.cell.future { background: none; box-shadow: inset 0 0 0 1px var(--track); }

.cell.future .cell-num { color: #bdbdbd; }

.empty { color: var(--ink-soft); }

/* --- Admin ------------------------------------------------------------------------------- */

/* --- Admin ---------------------------------------------------------------------------------
   Bootstrap's control shapes in the app's colours. A form select rather than the <details>
   dropdowns the public pages use: those are navigation and carry no value, and a form needs one
   submitted. Bootstrap's own answer to a dropdown inside a form is a styled <select> too. */

.admin-card { margin-bottom: 14px; }
.admin-card h2 { margin: 0 0 4px; padding: 0; border: 0; font-size: 20px; }

.notice { padding: 11px 14px; border-radius: var(--radius); background: #fff3cd; color: #664d03; }

.form-label {
    display: block;
    margin: 16px 0 6px;
    font-size: 13px;
    font-weight: 500;
}

.form-label .hint, p.hint { font-weight: 400; color: var(--ink-soft); font-size: 12px; }
p.hint { margin: 0 0 4px; }

.form-control, .form-select {
    display: block;
    width: 100%;
    max-width: 620px;
    padding: 8px 12px;
    font: inherit;
    font-size: 14px;
    color: var(--ink);
    background: var(--surface);
    border: 1px solid #ced4da;
    border-radius: var(--radius);
}

.form-control:focus, .form-select:focus {
    outline: 0;
    border-color: var(--secondary);
    box-shadow: 0 0 0 .2rem rgba(108, 117, 125, .25);
}

/* Bootstrap draws the caret as a background image rather than a glyph, so it needs no icon font. */
.form-select {
    appearance: none;
    padding-right: 34px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%236c757d' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 11px center;
    background-size: 14px;
}

textarea.form-control { max-width: 760px; resize: vertical; }

/* The service and module pickers are the SAME tag as an incident's module chips — .chip above,
   unchanged — because a picked service and a published one should not be two different objects.
   Only the unpicked state is new: the fill comes off and it reads as an outline.

   A grid of identical checkboxes made "which services are affected" something you had to read
   one row at a time. As tags the chosen set is one shape against another, legible at a glance.

   The checkbox is still there, still posting and still keyboard-reachable — clipped rather than
   display:none, which would take it out of the tab order and off the form entirely. */
.chips.chips-pick { margin-left: 0; max-width: 900px; }

.chip-pick { cursor: pointer; }

.chip-pick input {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0; border: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.chip-pick input:not(:checked) + .chip {
    background: var(--surface);
    border-color: #ced4da;
    color: var(--ink);
}

.chip-pick:hover input:not(:checked) + .chip { background: var(--bar); }

/* The tag is the control, so the focus ring has to land on it rather than on a 1px input
   parked off in the corner. */
.chip-pick input:focus-visible + .chip {
    outline: 0;
    box-shadow: 0 0 0 .2rem rgba(108, 117, 125, .35);
}

.chips-dense .chip { gap: 7px; padding: 5px 11px 5px 7px; font-size: 12px; }
.chips-dense .chip img { width: 18px; height: 18px; }

.form-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 20px; }
.form-actions.centred { justify-content: center; }

/* Type and Status are one decision in two halves — which thing is this, and where is it — so
   they sit on one row rather than stacking into two full-width dropdowns. */
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 0 18px; align-items: start; }
.form-row .form-select { max-width: 100%; }
@media (max-width: 700px) { .form-row { grid-template-columns: 1fr; } }

/* Two class selectors, so this beats both .form-control and textarea.form-control without
   reaching for !important. */
.form-control.form-wide { max-width: 100%; }

.planned-row { max-width: 100%; }

/* The preview is the real public block, so it needs the ground it sits on out there rather
   than the white of the form — otherwise a white card on a white card reads as one surface. */
.preview {
    padding: 12px;
    border-radius: var(--radius);
    background: var(--page);
}
.preview .incident { margin: 0; }
.preview .hint { display: block; }

.btn-secondary {
    padding: 9px 18px;
    font: inherit;
    font-size: 14px;
    border: 1px solid var(--secondary);
    border-radius: var(--radius);
    background: var(--secondary);
    color: #fff;
    cursor: pointer;
}

.btn-secondary:hover { background: #5c636a; border-color: #565e64; }

.btn-outline {
    padding: 9px 18px;
    font: inherit;
    font-size: 14px;
    border: 1px solid var(--secondary);
    border-radius: var(--radius);
    background: transparent;
    color: var(--secondary);
    cursor: pointer;
}

.btn-outline:hover { background: var(--secondary); color: #fff; }

.pin-panel > summary { list-style: none; cursor: pointer; }
.pin-panel > summary::-webkit-details-marker { display: none; }
.pin-panel > summary h2 { display: inline; }
.pin-panel > summary::after { content: " ▸"; color: var(--ink-soft); }
.pin-panel[open] > summary::after { content: " ▾"; }

.pins { margin: 8px 0 0; padding-left: 20px; font-size: 13px; color: var(--ink-soft); }
.pins .owned { color: var(--ink-soft); font-style: italic; }
.pins b { color: var(--ink); }

/* --- Quality floor ------------------------------------------------------------------------ */

a:focus-visible, select:focus-visible, button:focus-visible, input:focus-visible,
textarea:focus-visible, summary:focus-visible {
    outline: 2px solid var(--dark);
    outline-offset: 2px;
}

@media (max-width: 640px) {
    .container { padding-left: 1rem; padding-right: 1rem; }
    .wordmark { font-size: 17px; }
    .brand img { width: 26px; }
    .page { padding-top: 22px; padding-bottom: 48px; }
    .banner { font-size: 18px; padding: 15px 18px; }
    .months { flex-direction: column; }
    .component-head { flex-direction: column; align-items: flex-start; gap: 2px; }
}

@media (prefers-reduced-motion: reduce) {
    * { animation: none !important; transition: none !important; }
}

/* --- Planned maintenance ---------------------------------------------------------------------
   The announced window, which is a different fact from the window it actually ran in. Both are
   shown on a finished incident: "we said 22:00–02:00, it ran 22:04–03:10" is the honest record.
*/
.incident-plan { margin: 2px 0 0; font-size: 13px; color: var(--ink-soft); }

.upcoming-tag {
    display: inline-block;
    margin-left: 9px;
    padding: 2px 9px;
    border-radius: .375rem;
    background: var(--secondary);
    color: #fff;
    font-size: 11px;
    font-weight: 500;
    vertical-align: middle;
}

.live-incident.upcoming { border-left-color: #adb5bd; }

.planned-row { display: flex; align-items: center; gap: 10px; max-width: 620px; }
.planned-row .form-control { flex: 1 1 0; min-width: 0; }
.planned-sep { color: var(--ink-soft); font-size: 13px; }

/* --- Corrections and deletion ------------------------------------------------------------------
   Folded away because they belong to the morning after, not to running an incident. */
.update-fields { display: none; }

.preview-head { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; }

.btn-outline-danger {
    display: inline-block;
    padding: 6px 14px;
    font: inherit;
    font-size: 13px;
    text-decoration: none;
    border: 1px solid var(--danger);
    border-radius: var(--radius);
    background: transparent;
    color: var(--danger);
    cursor: pointer;
}
.btn-outline-danger:hover { background: var(--danger); color: #fff; }

.btn-danger {
    display: inline-block;
    padding: 9px 18px;
    font: inherit;
    font-size: 14px;
    text-decoration: none;
    border: 1px solid var(--danger);
    border-radius: var(--radius);
    background: var(--danger);
    color: #fff;
    cursor: pointer;
}
.btn-danger:hover { background: #bb2d3b; border-color: #b02a37; }

/* Corrections happen where the words are READ, not in a list of boxes further down that has to
   be matched up by eye against the timeline above it. The affordances are attached by script,
   so the served markup stays identical to the public page's. */
.preview .update { position: relative; padding-right: 28px; }

.update-body.editable { border-bottom: 1px dashed transparent; cursor: text; }
.preview .update:hover .update-body.editable { border-bottom-color: var(--border); }
.update-body.editable:focus {
    outline: 0;
    border-bottom-color: var(--secondary);
    background: var(--bar);
}

.update-remove {
    position: absolute;
    top: 2px;
    right: 2px;
    width: 20px;
    height: 20px;
    padding: 0;
    line-height: 1;
    font-size: 15px;
    color: var(--ink-soft);
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius);
    cursor: pointer;
    opacity: 0;
}
.preview .update:hover .update-remove, .update-remove:focus-visible { opacity: 1; }
.update-remove:hover, .update-remove:focus-visible { color: var(--danger); border-color: var(--danger); }

/* A native <dialog>: modal for real, focus trapped, Escape closes, no library. */
.modal {
    width: min(460px, calc(100vw - 32px));
    padding: 22px 24px;
    color: var(--ink);
    background: var(--surface);
    border: 0;
    border-left: 4px solid var(--danger);
    border-radius: var(--radius);
    box-shadow: 0 12px 40px rgba(0, 0, 0, .25);
}
.modal::backdrop { background: rgba(0, 0, 0, .45); }
.modal h2 { margin: 0 0 10px; padding: 0; border: 0; font-size: 19px; }
.modal p { margin: 0 0 8px; font-size: 14px; line-height: 1.5; }
.modal .form-actions { margin-top: 18px; }
.modal .btn-outline { line-height: 1.5; }

/* Title and Description are one labelled pair, but they are still two controls — flush against
   each other they read as one box with a line through it. */
input.form-wide + textarea.form-wide { margin-top: 4px; }

/* The row Save is about to add. Dashed, because it is a promise rather than a record — it must
   not be mistakable for something already published. */
.update.pending {
    padding: 6px 10px 6px 8px;
    border: 1px dashed var(--border);
    border-radius: var(--radius);
    background: var(--bar);
}
.update.pending .at { font-style: italic; }

/* What a service is FOR, on hover. Half of these are invisible to everyone but the person who
   wired them up, and the reader of a public incident is the least likely to know what Nutrient
   is. Breakout by overflow rather than by moving the element — no positioning library. */
.chip-noted { position: relative; }

.chip-pop {
    position: absolute;
    bottom: calc(100% + 7px);
    left: 50%;
    transform: translateX(-50%);
    z-index: 5;
    width: max-content;
    max-width: 260px;
    padding: 8px 11px;
    font-size: 12px;
    line-height: 1.45;
    text-align: left;
    color: var(--ink);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: 0 6px 18px rgba(0, 0, 0, .13);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
}

.chip-noted:hover .chip-pop,
.chip-pick input:focus-visible + .chip .chip-pop { opacity: 1; visibility: visible; }

.chips { overflow: visible; }

/* The key prompt. Narrow, because it asks one thing. */
.unlock { max-width: 460px; margin: 40px auto 0; }
.unlock .form-actions { justify-content: flex-start; }
