/* Mobile app styles. Reuses design tokens from ui/css/base.css. */
/* Every var() fallback below repeats the token's dark-theme value from
   base.css, so a missing stylesheet degrades to the intended look rather
   than to some other palette. */

/* /m/ follows [data-theme] on <html>, set before the first paint by the
   inline script in templates/mobile/_theme_script.html — the same
   "dmon-theme" localStorage contract the panel uses.

   color-scheme has to track it rather than be pinned. It is what makes
   UA-drawn chrome (the datetime-local picker, spin buttons, autofill
   backgrounds) match the page; hardcoded to dark it painted a dark picker
   onto a white card in light mode, and left unset it paints a light one
   under the dark theme's text. Declared on the root rather than on .m-app /
   .m-login-page because that is where the attribute lives, and because the
   default has to hold for a load where the script never ran: no attribute
   means the dark palette base.css defaults to, so dark it is. */
:root { color-scheme: dark; }
html[data-theme="light"] { color-scheme: light; }

/* One border colour for every outline control on /m/ — the form fields, the
   Acknowledge and Respond buttons, the canned-response chips. It is a
   variable rather than a value at each usage because the two themes need
   different tokens here, and overriding at the usage sites would mean
   re-stating every :focus rule at a higher specificity to keep the accent
   focus border.

   Dark keeps --border-default. Light cannot: #e2e8f0 is 1.18:1 against the
   page, under the 3:1 WCAG 1.4.11 wants of a control's visual boundary, and
   the login fields have nothing else marking them — see the light-theme
   section at the foot of this file. --text-secondary (#64748b, 4.8:1 on
   white) is a text token doing a line's job, which is not lovely; the
   alternatives were a literal hex or a new border token in base.css, and
   base.css belongs to the panel. */
:root { --m-control-border: var(--border-default, #30363d); }
html[data-theme="light"] { --m-control-border: var(--text-secondary, #64748b); }

/* --- Form controls --- */
/* One treatment for every text-entry control on /m/, login and respond
   panel alike. base.css gives inputs `color: inherit` and no background, and
   mobile.css does not load components.css, so without this they fall back to
   the UA's white box — i.e. --text-primary (#e6edf3) on white. Mirrors
   .form-input in ui/css/components.css, which is what the panel would use.
   16px, not 1rem: base.css sets html{font-size:14px} and iOS Safari
   auto-zooms the viewport when a focused input is under 16px. */
.m-login-card input,
.m-respond select,
.m-respond textarea,
.m-respond input,
.m-action select,
.m-action textarea,
.m-action input {
  font-size: 16px;
  background: var(--bg-primary, #0d1117);
  color: var(--text-primary, #e6edf3);
  border: 1px solid var(--m-control-border);
  border-radius: var(--radius-md, 6px);
}
/* No outline:none — the UA focus ring is the keyboard affordance and stays. */
.m-login-card input:focus,
.m-respond select:focus,
.m-respond textarea:focus,
.m-respond input:focus,
.m-action select:focus,
.m-action textarea:focus,
.m-action input:focus { border-color: var(--accent, #21ba61); }

/* --- Login (standalone page, no tab bar) --- */
/* 100vh ignores mobile Safari's collapsing URL bar; dvh tracks it. The vh
   line stays as the fallback for browsers that don't support dvh. */
.m-login-page { display: flex; min-height: 100vh; min-height: 100dvh; align-items: center; justify-content: center; padding: 1rem; }
.m-login-card { width: 100%; max-width: 22rem; }
.m-login-card h1 { text-align: center; margin-bottom: 1.5rem; }
.m-login-card label { display: block; margin: 0.75rem 0 0.25rem; font-size: 0.85rem; }
.m-login-card input { width: 100%; padding: 0.75rem; }
/* Same accent treatment as .m-btn-primary — the sign-in button is the app's
   first primary action and was rendering as a UA-default grey box against
   the themed inputs. Dark text on --accent, not white: white is 2.5:1. */
.m-login-card button { width: 100%; margin-top: 1.25rem; padding: 0.85rem; font-size: 1rem;
  border: 1px solid transparent; border-radius: var(--radius-md, 6px);
  background: var(--accent, #21ba61); color: #0d1117; font-weight: 600; }
.m-error { color: var(--severity-critical, #ef4444); margin-bottom: 0.5rem; }

/* --- App shell --- */
.m-app { padding-bottom: calc(4.5rem + env(safe-area-inset-bottom)); }
.m-header { position: sticky; top: 0; display: flex; justify-content: space-between; align-items: center; padding: calc(0.9rem + env(safe-area-inset-top)) 1rem 0.9rem; border-bottom: 1px solid var(--border-default, #30363d); background: var(--bg-primary, #0d1117); z-index: 10; }
.m-header-title { font-weight: 600; font-size: 1.05rem; }
.m-header-actions { display: flex; align-items: center; gap: 1rem; }
.m-logout-form { margin: 0; }
.m-logout { background: none; border: none; color: var(--text-secondary, #8b949e); font-size: 0.85rem; padding: 0.5rem; margin: -0.5rem; }
.m-content { padding: 1rem; }

/* --- Theme toggle --- */
/* 20px icon inside 0.5rem of padding is a 34px hit area, clearing the 24px
   WCAG 2.5.8 minimum; the matching negative margin keeps it from making the
   header taller, the same balance .m-logout strikes beside it. */
.m-theme-toggle { display: inline-flex; align-items: center; justify-content: center; background: none; border: none; color: var(--text-secondary, #8b949e); padding: 0.5rem; margin: -0.5rem; }
.m-theme-toggle svg { width: 20px; height: 20px; stroke: currentColor; fill: none; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
/* Which icon shows is pure CSS, keyed off the attribute the head script has
   already set — so it is right on the first paint, before any handler has
   run. Each icon is the theme the tap switches *to*: sun while dark, moon
   while light. The sun is shown unconditionally and the light theme hides
   it again, so a load with no [data-theme] at all — script blocked, or
   storage unreadable — still shows an icon rather than an empty button, and
   it is the one that matches the dark palette base.css falls back to. */
.m-theme-icon { display: none; }
.m-theme-icon-light { display: block; }
html[data-theme="light"] .m-theme-icon-light { display: none; }
html[data-theme="light"] .m-theme-icon-dark { display: block; }
/* Login has no header to sit in. Out of flow so it cannot stretch the
   centred card or land between the heading and the first field. */
.m-login-page .m-theme-toggle { position: absolute; top: calc(0.5rem + env(safe-area-inset-top)); right: 0.5rem; margin: 0; }

/* --- Bottom tab bar --- */
.m-tabbar { position: fixed; bottom: 0; left: 0; right: 0; display: flex; border-top: 1px solid var(--border-default, #30363d); background: var(--bg-secondary, #161b22); padding-bottom: env(safe-area-inset-bottom); z-index: 10; }
.m-tab { flex: 1; text-align: center; padding: 0.9rem 0; text-decoration: none; color: var(--text-secondary, #8b949e); font-size: 0.9rem; }
.m-tab-active { color: var(--text-primary, #e6edf3); font-weight: 600; }
.m-badge { display: inline-block; min-width: 1.3em; padding: 0 0.35em; border-radius: 1em; color: var(--severity-critical, #ef4444); background: var(--severity-critical-bg, rgba(239, 68, 68, 0.12)); font-size: 0.75rem; font-weight: 600; }

/* --- Client status cards --- */
.m-card { border: 1px solid var(--border-default, #30363d); background: var(--bg-secondary, #161b22); border-radius: var(--radius-lg, 8px); padding: 0.9rem; margin-bottom: 0.75rem; }
/* A client with anything down is the one thing worth spotting at 3am. */
.m-card.m-status-down { border-color: var(--status-down, #ef4444); }
.m-card-head { display: flex; justify-content: space-between; align-items: center; gap: 0.5rem; }
.m-card-title { font-weight: 600; min-width: 0; overflow-wrap: anywhere; }
.m-card-meta { font-size: 0.85rem; color: var(--text-secondary, #8b949e); margin-top: 0.25rem; }
.m-instance-list { list-style: none; margin: 0.6rem 0 0; padding: 0; font-size: 0.9rem; }
.m-instance-list li { display: flex; gap: 0.5rem; align-items: center; padding: 0.3rem 0; }
.m-instance-list .m-muted { margin-left: auto; padding-left: 0.5rem; text-align: right; }
/* --text-secondary, not --text-tertiary — the same call .m-refreshed and
   .m-section already make, and for the same reason. Tertiary is #6e7681 on
   the dark card (3.78:1, already under AA) and #94a3b8 on the light theme's
   white card (2.56:1, badly under). Secondary measures 5.6:1 dark and 4.8:1
   light. This is the "3 minutes ago" beside every instance and the "never
   checked" that means nobody is watching it — not decoration. */
.m-muted { color: var(--text-secondary, #8b949e); font-size: 0.85rem; }

/* Freshness signal for the 60s poll — a stopped clock means stale data.
   --text-secondary, not --text-tertiary: at 0.75rem (10.5px here) tertiary
   only just clears AA, and this is the one line that must stay legible. */
.m-refreshed { color: var(--text-secondary, #8b949e); font-size: 0.75rem; text-align: center; margin-top: 1rem; }

/* --- Status dots (mirror .status-dot--* in ui/css/components.css) --- */
.m-dot { width: 0.65rem; height: 0.65rem; border-radius: 50%; display: inline-block; flex-shrink: 0; }
.m-dot-up { background: var(--status-up, #22c55e); }
.m-dot-down { background: var(--status-down, #ef4444); }
.m-dot-stale { background: var(--status-stale, #f59e0b); }
.m-dot-unknown { background: var(--status-unknown, #6b7280); }

/* --- Alerts list --- */
/* --text-secondary rather than the usual opacity trick: these headings sit
   on --bg-primary and fading them below AA makes the Active/Resolved split
   hard to find on a phone screen at 3am. */
.m-section { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-secondary, #8b949e); margin: 1.1rem 0 0.5rem; }
.m-section:first-child { margin-top: 0; }
/* Whole card is the tap target — base.css colours <a> green, so reset it. */
.m-alert-row { display: block; text-decoration: none; color: inherit; }
/* Severity reads off the left edge without needing the badge to be legible. */
.m-sev-critical { border-left: 3px solid var(--severity-critical, #ef4444); }
.m-sev-warning { border-left: 3px solid var(--severity-warning, #f59e0b); }
.m-sev-info { border-left: 3px solid var(--severity-info, #06b6d4); }
/* De-emphasis is done with explicit tokens, never opacity — the same call
   made on .m-section above. opacity fades the text too, and it compounds:
   0.65 would drop .m-card-meta to ~3.1:1 and .m-muted to ~2.3:1, both under
   AA on the one screen read one-handed at 3am. Receding the card's own
   surface and border says "already dealt with" without touching contrast. */
.m-resolved { background: var(--bg-primary, #0d1117); border-color: var(--border-muted, #21262d); }
.m-resolved .m-card-title { font-weight: 500; color: var(--text-secondary, #8b949e); }
.m-sev-badge { flex-shrink: 0; font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.04em; font-weight: 600; padding: 0.1rem 0.45rem; border-radius: var(--radius-sm, 4px); }
.m-sev-badge-critical { color: var(--severity-critical, #ef4444); background: var(--severity-critical-bg, rgba(239, 68, 68, 0.12)); }
.m-sev-badge-warning { color: var(--severity-warning, #f59e0b); background: var(--severity-warning-bg, rgba(245, 158, 11, 0.12)); }
.m-sev-badge-info { color: var(--severity-info, #06b6d4); background: var(--severity-info-bg, rgba(6, 182, 212, 0.12)); }
.m-ack { color: var(--status-up, #22c55e); }

/* --- Alert detail --- */
.m-alert-message { margin-top: 0.6rem; font-size: 0.92rem; overflow-wrap: anywhere; }

/* Stacked, not side by side: full-width targets are easier to hit one-handed,
   and an open Respond panel inside a flex row would stretch the Acknowledge
   button to match its height. */
.m-actions { display: flex; flex-direction: column; gap: 0.6rem; margin: 0.9rem 0; }
.m-actions form { margin: 0; }
.m-btn { display: block; width: 100%; padding: 0.8rem; text-align: center; border-radius: var(--radius-md, 6px); border: 1px solid var(--m-control-border); background: transparent; color: inherit; font-size: 0.95rem; }
/* #0d1117 rather than white or a var: white on --accent is 2.5:1, well under
   AA — the same trap the severity badges fell into. A literal is
   used because the obvious token (--bg-primary) flips to near-white under
   [data-theme="light"] — this foreground has to stay dark whatever the
   background token does. It clears AA against both accents: 7.4:1 on the
   dark #21ba61 and 5.0:1 on the light theme's #1a9650. */
.m-btn-primary { background: var(--accent, #21ba61); border-color: transparent; color: #0d1117; font-weight: 600; }

/* <details>/<summary> drives the Respond panel, so it needs no JS. The
   summary is styled as a button, and the disclosure triangle is dropped so
   it does not sit inside one. */
.m-respond, .m-action { min-width: 0; }
.m-respond > summary, .m-action > summary { cursor: pointer; list-style: none; }
.m-respond > summary::-webkit-details-marker,
.m-action > summary::-webkit-details-marker { display: none; }
.m-respond form, .m-action form { margin-top: 0.6rem; }
.m-respond label, .m-action label { display: block; margin: 0.6rem 0 0.2rem; font-size: 0.85rem; color: var(--text-secondary, #8b949e); }
/* Surface, border and font-size come from the shared form-control rule at
   the top of this file — the login inputs get the identical treatment.
   .m-action rides along everywhere .m-respond does: resolve/close/assign
   are the same disclosure-panel-with-a-form shape as Respond. */
.m-respond select, .m-respond textarea, .m-respond input,
.m-action select, .m-action textarea, .m-action input { width: 100%; padding: 0.6rem; }
.m-respond textarea, .m-action textarea { resize: vertical; }
.m-respond .m-btn-primary, .m-action .m-btn-primary { margin-top: 0.8rem; }
/* The secondary button inside a panel (Assign to me) needs the same
   breathing room the primary gets, without restyling .m-btn globally. */
.m-action form .m-btn { margin-top: 0.6rem; }
.m-action .m-muted { margin: 0.5rem 0 0; font-size: 0.85rem; }
.m-canned { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0.6rem 0; }
.m-canned-btn { width: auto; font-size: 0.8rem; padding: 0.35rem 0.6rem; border-radius: 1rem; border: 1px solid var(--m-control-border); background: transparent; color: inherit; }

.m-timeline-item { padding: 0.45rem 0; border-bottom: 1px solid var(--border-muted, #21262d); font-size: 0.9rem; display: flex; gap: 0.5rem; flex-wrap: wrap; }
/* --text-secondary, not opacity: same call as .m-section and .m-resolved.
   opacity: 0.7 over --text-secondary would land near 3:1 on --bg-primary,
   and the detail line is where "failed: SMTP timeout" actually lives. */
.m-timeline-when { color: var(--text-secondary, #8b949e); min-width: 2.5rem; }
.m-timeline-detail { color: var(--text-secondary, #8b949e); width: 100%; overflow-wrap: anywhere; }

/* --- Flash messages --- */
.m-flash { padding: 0.6rem 0.9rem; border-radius: var(--radius-md, 6px); margin-bottom: 0.75rem; border: 1px solid var(--border-default, #30363d); background: var(--bg-elevated, #21262d); }
.m-flash-error { border-color: var(--severity-critical, #ef4444); background: var(--severity-critical-bg, rgba(239, 68, 68, 0.12)); }
.m-flash-success { border-color: var(--status-up, #22c55e); background: var(--status-up-bg, rgba(34, 197, 94, 0.12)); }
/* "Saved, but nobody was emailed" is neither a success nor a hard failure,
   and respond is the one action where the difference matters. */
.m-flash-warning { border-color: var(--severity-warning, #f59e0b); background: var(--severity-warning-bg, rgba(245, 158, 11, 0.12)); }

/* --- Light theme corrections --- */
/* Everything above is written in tokens, so [data-theme="light"] carries
   most of /m/ across on its own. These are the places where it does not,
   and each is scoped to html[data-theme="light"] in this file so that
   /panel/, which loads base.css but not this, is untouched.

   1. Severity and status hues. base.css deliberately does not re-tune them
   between themes — hue is how they carry meaning, and on dark surfaces they
   measure fine. On a white card they do not. Against --bg-secondary
   (#ffffff) in the light theme:

     --severity-critical #ef4444  3.8:1  .m-error, .m-badge, the sev badge
     --severity-warning  #f59e0b  2.2:1  the warning badge, the stale dot
     --severity-info     #06b6d4  2.4:1  the info badge
     --status-up         #22c55e  2.3:1  "Ack'd", the up dot

   All of that is body-sized text needing 4.5:1, or dots and 3px severity
   rails needing 3:1 as non-text graphics. Every one fails its own bar, and
   the tinted -bg backgrounds they sit on make it marginally worse, not
   better. The fix keeps the hue and takes it down to a shade a white page
   can hold — red still reads as red. After, against #ffffff and against the
   matching -bg tint over white:

     #b91c1c 6.5 / 5.8   #b45309 5.0 / 4.7   #0e7490 5.4 / 5.0
     #15803d 5.0 / 4.7   #4b5563 7.6 (dot only)                        */
html[data-theme="light"] {
  --severity-critical: #b91c1c;
  --severity-warning: #b45309;
  --severity-info: #0e7490;
  --status-up: #15803d;
  --status-down: #b91c1c;
  --status-stale: #b45309;
  --status-unknown: #4b5563;
}

/* 2. Resolved alert cards. .m-resolved recedes a card by dropping its fill
   to --bg-primary: in dark that is #0d1117 under a #161b22 card, and the
   --border-muted edge still holds the shape at 1.24:1 against the page. In
   light the same two moves all but erase it — the fill becomes exactly the
   page colour, and --border-muted (#f1f5f9) is 1.05:1 on that page, so the
   card loses its outline as well as its fill and the resolved list reads as
   loose text. Keep the receding fill, which is the de-emphasis and which
   also keeps the resolved title's --text-secondary at 4.6:1 (a --bg-tertiary
   fill would drop it to 4.3:1, under AA); put the normal border back so
   there is still a card there. 1.18:1 on the page, in line with dark. */
html[data-theme="light"] .m-resolved { border-color: var(--border-default); }

/* 3. Field surfaces. The shared control rule fills inputs with --bg-primary,
   which in light is the page colour — so the three login fields would be
   page-coloured boxes whose only boundary is --m-control-border. That
   boundary now clears 3:1, but a field the same colour as the page behind it
   still does not look like somewhere to type. Give them the card surface;
   in the respond panel, which sits on the page too, this reads the same. */
html[data-theme="light"] .m-login-card input,
html[data-theme="light"] .m-respond select,
html[data-theme="light"] .m-respond textarea,
html[data-theme="light"] .m-respond input,
html[data-theme="light"] .m-action select,
html[data-theme="light"] .m-action textarea,
html[data-theme="light"] .m-action input { background: var(--bg-secondary); }

/* --- Filter chips (alerts list) ------------------------------------------
   Horizontal scroll rather than wrap: two rows of chips already cost the
   height of an alert card, and the off-screen chips are the rarely-used
   ones. #0d1117 on --accent for the same reason as .m-btn-primary — white
   on the accent is 2.5:1. --m-control-border, not --border-default: chips
   are outline controls, and that token exists because --border-default is
   1.18:1 in light theme — under the 3:1 floor. */
.m-chip-row { display: flex; gap: 8px; overflow-x: auto; padding: 4px 0 10px; }
.m-chip { padding: 4px 12px; border-radius: 14px; border: 1px solid var(--m-control-border, #30363d);
          font-size: 0.85rem; white-space: nowrap; text-decoration: none; color: inherit; }
.m-chip-on { background: var(--accent, #21ba61); color: #0d1117; border-color: transparent; }
.m-chip-gap { flex: 0 0 8px; }

/* --- Alert detail: failed jobs / details blocks ---------------------------
   Structured alert_data rendered inside the alert card. The title reuses the
   .m-section treatment's job at card scale; body lines are .m-card-meta, so
   no new text colours are introduced (and none of the AA arguments above
   need re-making). The full error text lives behind a <details> — same
   no-JS disclosure call as the Respond panel, because the interesting error
   is often a 1KB ODBC stack and the summary line is what triage needs. The
   marker is kept (unlike .m-respond's) so the truncated line visibly says
   "there is more". */
.m-detail-block { margin-top: 0.85rem; }
.m-detail-title { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-secondary, #8b949e); margin: 0 0 0.4rem; }
.m-job { margin-bottom: 0.7rem; }
.m-job:last-child { margin-bottom: 0; }
.m-job-error summary { cursor: pointer; font-size: 0.85rem; color: var(--text-secondary, #8b949e); overflow-wrap: anywhere; }
.m-job-error p { margin: 0.3rem 0 0; font-size: 0.85rem; overflow-wrap: anywhere; }
/* External data again: an unbroken 300-char value (a path, a connection
   string) must wrap inside the card, not scroll the whole page sideways —
   the same guard .m-alert-message carries for the same reason. */
.m-detail-block .m-card-meta { overflow-wrap: anywhere; }
