/* SMS1919 design system — Phase 1 shell + components.
   Plain CSS + custom properties, evergreen browsers only, no build step.
   NEW class names only — does not restyle existing default.css classes. */

/* Self-hosted variable brand font (latin subset incl. æ ø å) — no third-party CDN (GDPR). */
@font-face {
  font-family: "Geist";
  src: url("fonts/geist.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

:root {
  /* Brand: set per-request as inline style on .app-shell (from css_menu_background).
     This is the fallback / default identity (SMS1919 orange #F29721). */
  --brand: #F29721;
  /* Derived accents (work for any brand hue; guard darkens too-light brands). */
  --brand-text:   color-mix(in srgb, var(--brand) 78%, black);
  --brand-tint:   color-mix(in srgb, var(--brand) 10%, white);
  --brand-strong: color-mix(in srgb, var(--brand) 88%, black);
  /* Text/icon color that sits ON the brand color. White per design preference. */
  --on-brand: #ffffff;

  /* Neutral surfaces / text */
  --bg:        #f7f8fa;
  --surface:   #ffffff;
  --border:    #e6e8ec;
  --hairline:  #f0f1f3;
  --text:      #1a1d24;
  --text-soft: #4a4f5a;
  --text-mute: #9095a0;

  /* Notices */
  --warn-bg: #fff7ed; --warn-border: #fed7aa; --warn-text: #9a3412; --warn-accent: #ea7317;

  /* State / surface tokens (light defaults; dark values live in [data-theme="dark"]) */
  --danger-bg: #fdeceb; --danger-border: #f5c6c2; --danger-text: #b3261e; --danger-accent: #c0271f;
  --ok-bg: #e7f5ed; --ok-border: #bfe3cd; --ok-text: #0d7a4f;
  --field-border: #d6d9df;
  --row-alt: #fafbfc; --row-hover: #f4f6f8;
  --overlay: rgba(15,23,42,.45);

  /* Shape / type */
  --radius: 10px; --radius-sm: 8px; --shadow: 0 1px 3px rgba(16,24,40,.06);
  --font: "Geist", system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --sidebar-w: 220px;
}

/* ---- Dark theme: redefine surface/text/state tokens. --brand is untouched so it still
   resolves per-reseller; only its derived tints re-aim at the dark surface. ---- */
[data-theme="dark"] {
  --bg: #0e1116;
  --surface: #171b22;
  --border: #2a303a;
  --hairline: #20262e;
  --text: #d4d9e1;
  --text-soft: #aab2bf;
  --text-mute: #79818f;
  --warn-bg: #2a1d10; --warn-border: #5b3d1c; --warn-text: #f1b97f; --warn-accent: #f59e42;
  --danger-bg: #2a1416; --danger-border: #5b2622; --danger-text: #f1a8a3; --danger-accent: #d9534f;
  --ok-bg: #15281d; --ok-border: #2c5b3f; --ok-text: #4ec18b;
  --field-border: #2f3742;
  --row-alt: #1b2027; --row-hover: #20262e;
  --overlay: rgba(0,0,0,.6);
  --shadow: 0 1px 3px rgba(0,0,0,.45);
  --brand-text:   color-mix(in srgb, var(--brand) 70%, white);
  --brand-tint:   color-mix(in srgb, var(--brand) 22%, var(--surface));
  --brand-strong: color-mix(in srgb, var(--brand) 92%, white);
}

/* ---- App shell ---- */
.app-shell { display: grid; grid-template-columns: var(--sidebar-w) 1fr; min-height: 100vh; font-family: var(--font); color: var(--text); background: var(--bg); }
/* Re-derive the brand tints here so a per-reseller --brand (set inline on .app-shell) flows into them
   too. The :root copies resolve var(--brand) at :root, baking in the default brand; re-declaring on
   .app-shell recomputes them against the overridden --brand. Ratios mirror :root / [data-theme=dark]. */
.app-shell { --brand-text: color-mix(in srgb, var(--brand) 78%, black); --brand-tint: color-mix(in srgb, var(--brand) 10%, white); --brand-strong: color-mix(in srgb, var(--brand) 88%, black); }
[data-theme="dark"] .app-shell { --brand-text: color-mix(in srgb, var(--brand) 70%, white); --brand-tint: color-mix(in srgb, var(--brand) 22%, var(--surface)); --brand-strong: color-mix(in srgb, var(--brand) 92%, white); }
.app-sidebar { background: var(--surface); border-right: 1px solid var(--border); display: flex; flex-direction: column; position: sticky; top: 0; align-self: start; height: 100vh; overflow-y: auto; }
.app-main { padding: 28px 32px; min-width: 0; background: url("/images/watermark.svg") right -20px bottom -10px / 340px no-repeat fixed; }

/* ---- Brand / logo band ---- */
.brand-band { background: var(--brand); padding: 18px 16px; text-align: center; }
.brand-band img { max-width: 100%; height: auto; display: block; margin: 0 auto; cursor: pointer; }
.brand-band .brand-wordmark { color: var(--on-brand); font-weight: 700; font-size: 18px; letter-spacing: .4px; cursor: pointer; }

/* ---- Nav ---- */
.app-nav { padding: 12px 10px; }
.nav-section { font-size: 10px; text-transform: uppercase; letter-spacing: 1.2px; color: var(--text-mute); margin: 12px 4px 6px; }
.nav-section:first-child { margin-top: 2px; }
.nav-item { display: block; padding: 8px 11px; margin: 2px 0; border-radius: var(--radius-sm); font-size: 13px; color: var(--text-soft); text-decoration: none; cursor: pointer; border-left: 3px solid transparent; }
.nav-item:hover { background: var(--hairline); color: var(--text); }
.nav-item.is-active { background: var(--brand-tint); color: var(--brand-text); font-weight: 600; border-left-color: var(--brand); }
/* Collapsible groups: header toggles, .nav-group-items folds via .is-open */
.nav-item:has(+ .nav-group-items.is-open) { font-weight: 600; color: var(--text); }
.nav-group-items { display: none; margin: 2px 0 6px 12px; padding-left: 10px; border-left: 2px solid var(--border); }
.nav-group-items.is-open { display: block; }

/* Sidebar footer (logout pinned to bottom) */
.app-sidebar-footer { margin-top: auto; padding: 10px; border-top: 1px solid var(--border); }
.logout-link { display: flex; align-items: center; gap: 9px; padding: 8px 11px; border-radius: var(--radius-sm); font-size: 13px; color: var(--text-soft); text-decoration: none; cursor: pointer; }
.logout-link:hover { background: var(--hairline); color: var(--text); text-decoration: none; }
.logout-link svg { width: 16px; height: 16px; flex-shrink: 0; opacity: .65; }

/* ---- Page header (emitted by Header()) ---- */
/* pointer-events:none lets clicks fall through the full-width header block to the floated action
   buttons it overlaps (e.g. Slet/Tøm gruppen). The header has no interactive content of its own. */
.page-header { margin-bottom: 24px; padding-bottom: 16px; position: relative; pointer-events: none; }
.page-header::after { content: ""; position: absolute; left: 0; bottom: 0; width: 34px; height: 3px; border-radius: 2px; background: var(--brand); }
.page-header h1 { font-family: var(--font); font-size: 15px; font-weight: 600; letter-spacing: .12em; text-transform: uppercase; color: var(--text-soft); margin: 0; }
.page-header .subhead { font-size: 13px; color: var(--text-mute); margin-top: 7px; }
.page-header .subhead.is-error { color: var(--danger-accent); }
.page-header .subhead.is-ok    { color: var(--brand-text); }
.page-header .subhead.is-eval  { color: var(--ok-text); }

/* ---- Cards ---- */
.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); padding: 16px; }

/* ---- Modal (banner-headed popup): brand-colored title bar, body, hairline, footer actions ---- */
.modal-overlay { position: fixed; inset: 0; z-index: 105; display: none; align-items: center; justify-content: center; background: var(--overlay); backdrop-filter: blur(3px); }
.modal-overlay.is-open { display: flex; }
.modal-card { background: var(--surface); border-radius: var(--radius); box-shadow: 0 24px 60px -24px rgba(16,24,40,.35); width: 90%; max-width: 360px; overflow: hidden; animation: modalIn .22s cubic-bezier(.2,.7,.2,1) both; }
@keyframes modalIn { from { opacity: 0; transform: translateY(10px) scale(.98); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .modal-card { animation: none; } }
.modal-head { background: var(--brand); color: var(--on-brand); padding: 14px 20px; font-size: 16px; font-weight: 600; letter-spacing: .2px; }
.modal-body { padding: 22px 20px; color: var(--text-soft); font-size: 13px; }
.modal-foot { padding: 13px 20px; border-top: 1px solid var(--border); display: flex; justify-content: flex-end; gap: 10px; }

/* Brand spinner — CSS replacement for ajax-loader.gif (16px to match exactly, no content shift; brand orange, theme-aware). */
.spinner { display: inline-block; width: 16px; height: 16px; vertical-align: middle; box-sizing: border-box; border: 2px solid color-mix(in srgb, var(--brand) 22%, transparent); border-top-color: var(--brand); border-radius: 50%; animation: spin .6s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* Phosphor icons: near-black (text colour) at 80% opacity, lifting to 100% on hover — a subtle
   strengthen, not a colour shift. inline-block stops the <a> hover-underline striking the glyph.
   Icons with an explicit inline colour (danger/ok) keep that colour; only the opacity changes. */
.ph { display: inline-block; color: var(--text); opacity: .6; transition: opacity .25s ease; }
a:hover .ph, .ph:hover { opacity: .95; }

/* ---- Buttons ---- */
.btn { display: inline-block; font-size: 13px; font-weight: 500; padding: 9px 16px; border-radius: var(--radius-sm); cursor: pointer; border: 1px solid transparent; text-decoration: none; }
.btn-primary { background: var(--brand-strong); color: var(--on-brand); }
/* Spinner inside a primary button sits on the orange fill, so recolor its ring to the button's
   text colour (white); the default brand-orange ring would be invisible. (in-button login loader) */
.btn-primary .spinner { border-color: color-mix(in srgb, var(--on-brand) 35%, transparent); border-top-color: var(--on-brand); }
.btn-ghost { background: var(--surface); color: var(--text-soft); border-color: var(--border); }
/* .btn used on <a> — beat default.css A:link color + hover underline */
a.btn:link, a.btn:visited, a.btn:hover { text-decoration: none; }
a.btn-ghost:link, a.btn-ghost:visited { color: var(--text-soft); }
a.btn-primary:link, a.btn-primary:visited { color: var(--on-brand); }

/* ---- Forms ---- */
.field { margin-bottom: 14px; }
.field > label { display: block; font-size: 11px; font-weight: 600; color: var(--text-soft); margin-bottom: 5px; }
.field input[type=text], .field input[type=password], .field input[type=email], .field select, .field textarea {
  width: 100%; box-sizing: border-box; border: 1px solid var(--field-border); border-radius: var(--radius-sm); padding: 9px 11px; font: inherit; font-size: 13px; color: var(--text-soft); background: var(--surface); }
.field input:focus, .field select:focus, .field textarea:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 18%, transparent); }
/* override legacy default.css input{height:20px;width:180px} */
.field input[type=text], .field input[type=password], .field input[type=email], .field select { height: auto; }
input[type=checkbox], input[type=radio] { width: auto; height: auto; margin: 0 7px 0 0; vertical-align: middle; }
/* larger inputs on the login card */
.auth-card .field input { padding: 11px 13px; font-size: 15px; }

/* Inline availability/validation status pill (keyword / username / password / graph path).
   Replaces the legacy flat_* validation icon images. State set from JS:
   className 'kw-status kw-status-<checking|ok|taken>' + innerHTML ('✓ Ledig' / '✗ Optaget'). */
.kw-status:empty { display: none; }
.kw-status { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; font-weight: 600; padding: 5px 11px; border-radius: 7px; white-space: nowrap; }
.kw-status-checking { background: var(--hairline); color: var(--text-mute); font-weight: 400; }
.kw-status-ok { background: var(--brand-tint); color: var(--brand-text); }
.kw-status-taken { background: var(--danger-bg); color: var(--danger-text); }

/* Quirks-mode fix: these legacy pages have no doctype, so the UA stylesheet applies
   table { color: -internal-quirk-inherit } and tables do NOT inherit color from .app-shell —
   so table text fell back to browser-black and never picked up var(--text) (broke dark mode).
   Force normal inheritance. (Font is already worked around by default.css setting it on table.) */
table { color: inherit; }

/* ---- Data table ---- */
.data-table { width: 100%; border-collapse: collapse; }
.data-table th { font-size: 10px; text-transform: uppercase; letter-spacing: .5px; color: var(--text-mute); text-align: left; font-weight: 600; padding: 10px 8px; border-bottom: 1px solid var(--hairline); }
.data-table td { font-size: 13px; color: var(--text-soft); padding: 11px 8px; border-bottom: 1px solid var(--hairline); }
.data-table tr:hover td { background: var(--row-alt); }

/* ---- Tabs (emitted by TabbedHeader()) ---- */
.tabbar { display: flex; gap: 22px; border-bottom: 1px solid var(--border); margin: 4px 0 14px; }
.tab { font-size: 13px; color: var(--text-mute); padding-bottom: 9px; border-bottom: 2px solid transparent; cursor: pointer; }
.tab.is-active { color: var(--brand-text); font-weight: 600; border-bottom-color: var(--brand); cursor: default; }

/* Column-header label (emitted by SingleTabbedHeader) */
.th-label { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .4px; color: var(--text-mute); }

/* Legacy data-table chrome, restyled (used across list pages) */
td.Header { background: transparent; border-bottom: 1px solid var(--border); padding: 9px 8px; height: auto; vertical-align: middle; white-space: nowrap; }
td.Footer { background: transparent; border-top: 1px solid var(--border); padding: 8px; font-weight: normal; }
.FirstRow, .SecondRow { background: var(--surface); height: auto; }
.SecondRow { background: var(--row-alt); }
/* Dark mode: drop the zebra stripe so rows share one surface and the hairline divides them evenly.
   The stripe (row-alt) sat between surface and the lighter hairline, so the hairline blended into the
   lighter row and made it look taller. Light mode keeps its near-invisible stripe. */
[data-theme="dark"] .SecondRow { background: var(--surface); }
.FirstRow > td, .SecondRow > td { border-bottom: 1px solid var(--hairline); padding: 9px 8px; }
/* Row hover highlight — applies in lists and forms alike (consistent). The old form-only reset was
   removed: it disabled hover on data lists that happen to be wrapped in a <form> (groups/manage etc.),
   and once dark mode dropped the stripe it left SecondRow resetting to a now-wrong colour. */
tr.FirstRow:hover > td, tr.SecondRow:hover > td { background: var(--row-hover); }

/* Frame legacy list/section/form tables as rounded cards — airier and in line with the card design.
   Targets tables carrying the legacy header OR footer cells (covers list pages AND tab/form layouts,
   where the tabbar is the header so only a footer is present). Corners are clipped via overflow on a
   separate-border table so the row backgrounds round off cleanly. */
table:has(td.Header, td.Footer) {
  border-collapse: separate; border-spacing: 0;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  overflow: hidden; box-shadow: var(--shadow); margin-bottom: 18px;
}
table:has(td.Header, td.Footer) td.Header { padding: 13px 16px; }
table:has(td.Header, td.Footer) .FirstRow > td, table:has(td.Header, td.Footer) .SecondRow > td { padding: 12px 16px; }
/* Footer = action bar (submit) on forms, empty strip on lists. A top hairline separates the action
   bar from the fields above; empty list footers are collapsed below, so it never shows on lists. */
table:has(td.Header, td.Footer) td.Footer { border-top: 1px solid var(--border); padding: 10px 16px; vertical-align: middle; }
table:has(td.Header, td.Footer) td.Footer:empty { padding: 0; }
/* A footer row whose cells are all empty (a list with no action bar) is just dead space — drop the
   whole row so the card bottom falls on the last data row and clips to the rounded corner cleanly.
   Self-correcting: if any footer cell holds a button/text it's no longer :empty, so the row stays. */
table:has(td.Header, td.Footer) tr:has(> td.Footer):not(:has(td.Footer:not(:empty))) { display: none; }
/* Clean bottom edge: drop the divider on the last data row before the footer, so its only separator
   is the footer's own border-top (no doubled hairline). Select that row by relationship — a
   .FirstRow/.SecondRow with no later data-row sibling — NOT by position. Position (:nth-last-child(2))
   broke on results pages: result.asp emits the delivery-checker <script> as a direct <table> child
   between the last data row and the footer, and since <script> is not foster-parented out of a table
   it took the :nth-last-child(2) slot, leaving the real last row's border-bottom to stack with the
   footer's border-top into a doubled line. */
table:has(td.Footer) tr.FirstRow:not(:has(~ .FirstRow)):not(:has(~ .SecondRow)) > td,
table:has(td.Footer) tr.SecondRow:not(:has(~ .FirstRow)):not(:has(~ .SecondRow)) > td { border-bottom: none; }
table:has(td.Header, td.Footer) tr:last-child > td { border-bottom: none; }
/* Data cells carry the .FirstRow/.SecondRow border-bottom (the row divider) AND the legacy
   .Row/.List border-top; with border-collapse:separate those stack into a 2px line. Drop the top
   one in the card so border-bottom is the single 1px divider (also de-doubles the header seam). */
table:has(td.Header, td.Footer) .Row, table:has(td.Header, td.Footer) .List { border-top: none; }
/* Icon rows ride high: the 18px Phosphor icons sit at vertical-align:middle, but data cells default to
   baseline, so action-icon columns (gear/handshake/chart/…) don't line up with the text columns.
   Vertically center the column cells — but ONLY in card tables that actually contain an icon (text-only
   list/form tables are left untouched), and never override an explicit valign="top"/"bottom". */
table:has(td.Header, td.Footer):has(.ph) td[class*="Column"]:not([valign]) { vertical-align: middle; }

/* Column-trick forms: standalone text fields were pinned to the legacy 180px. Let them fill their column (220px floor) so they're balanced in the airy layout. Cells with inline controls (checkbox/radio/button) and explicitly-sized inputs are left untouched so nothing reflows. */
form td[class*="Column"]:not(:has(input[type=checkbox], input[type=radio], input[type=submit], input[type=button], button)) > input[type=text]:not([style*="width"]),
form td[class*="Column"]:not(:has(input[type=checkbox], input[type=radio], input[type=submit], input[type=button], button)) > textarea:not([style*="width"]) {
  width: 100%; min-width: 220px; box-sizing: border-box;
}
/* "Field + inline toggle" cells (e.g. MaxMembers + "Ingen begrænsning"): make the text input block so the checkbox/radio option drops to its own line below it — independent of column width. The old layout relied on the narrow 180px column to force that wrap, which broke once columns could widen. */
form td[class*="Column"] > input[type=text]:has(~ input[type=checkbox]):not([style*="width"]),
form td[class*="Column"] > input[type=text]:has(~ input[type=radio]):not([style*="width"]) {
  display: block; margin-bottom: 6px;
}
/* Legacy column-layout classes (TabbedColumn -> FirstColumn/Column): dashed -> clean hairline */
.Row, .List { border-top: 1px solid var(--hairline); padding: 9px 8px; vertical-align: middle; }
.LeftColumnSeperated { border-left: 1px solid var(--border); }

/* Legacy buttons (Back()/BackLink() emit input.Button; plus bare submit/button) -> clean neutral button */
input.Button, input[type=submit], input[type=button], input[type=reset], button {
  background: var(--surface); color: var(--text-soft); border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 8px 16px; height: auto; width: auto; font: inherit; font-size: 13px; font-weight: 500; cursor: pointer; }
input.Button:hover, input[type=submit]:hover, input[type=button]:hover, input[type=reset]:hover, button:hover {
  background: var(--hairline); color: var(--text); }
/* Legacy fixed widths clipped these: let "Tilføj" add-buttons size to their text, and widen the shared #recipient add-field so "Email/Mobilnummer" isn't cut off. */
input[type=button][value*="Tilføj"], input[type=submit][value*="Tilføj"] { width: auto !important; }
input#recipient { width: 200px !important; }

/* SMS message composer (InputSMS()): full-width textarea + a tidy meta row (besked count left, char counter right) instead of the old floated 9px spans. */
.sms-input { max-width: 600px; }
.sms-input textarea { width: 100%; box-sizing: border-box; resize: vertical; }
.sms-input-meta { display: flex; justify-content: space-between; align-items: center; font-size: 11px; font-weight: 600; color: var(--text-mute); margin-top: 6px; }
.sms-input-meta span[disabled] { color: var(--text-mute); }

/* Legacy <select> dropdowns -> modern (width left to inline/default so narrow date/page selects keep their size) */
select { background: var(--surface); border: 1px solid var(--field-border); border-radius: var(--radius-sm); padding: 6px 8px; height: auto; font: inherit; font-size: 13px; color: var(--text-soft); }
select:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 18%, transparent); }

/* Native file inputs (megabulk upload + others): clean field + a modern ghost-style button */
input[type=file] { font: inherit; font-size: 13px; color: var(--text-soft); background: transparent; border: none; width: auto; height: auto !important; padding: 0; }
input[type=file]::file-selector-button { font: inherit; font-size: 13px; font-weight: 500; background: var(--surface); color: var(--text-soft); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 8px 14px; margin-right: 10px; cursor: pointer; }
input[type=file]::file-selector-button:hover { background: var(--hairline); color: var(--text); }

/* Header action icons: a floated <img> right before the title was offset (margin-top) for the old, taller header; realign so it no longer crosses the new .page-header border. Scoped to <img> so div-wrapped icon groups are unaffected. */
img[style*="float: right"]:has(+ .page-header), img[style*="float:right"]:has(+ .page-header) { margin-top: 0 !important; }

/* Bare text inputs & textareas (outside .field): modern appearance. Width left intact so existing layouts aren't disturbed. */
input[type=text], input[type=password], input[type=email], input:not([type]), textarea {
  box-sizing: border-box; background: var(--surface); border: 1px solid var(--field-border); border-radius: var(--radius-sm); padding: 7px 10px; font: inherit; font-size: 13px; color: var(--text-soft); }
input[type=text], input[type=password], input[type=email], input:not([type]) { height: auto; }
input[type=text]:focus, input[type=password]:focus, input[type=email]:focus, input:not([type]):focus, textarea:focus {
  outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 18%, transparent); }

/* ---- SMS phone mock: pure-CSS "how to use" illustration (replaces old iOS screenshots) ---- */
.sms-mock { width: 188px; background: var(--surface); border: 1px solid var(--border); border-radius: 26px; box-shadow: 0 12px 32px -16px rgba(16,24,40,.30); padding: 11px 10px 7px; }
.sms-mock-speaker { width: 36px; height: 4px; border-radius: 3px; background: var(--border); margin: 2px auto 9px; }
.sms-mock-screen { background: var(--bg); border-radius: 16px; overflow: hidden; border: 1px solid var(--hairline); }
.sms-mock-bar { text-align: center; font-size: 12px; font-weight: 600; color: var(--text); padding: 9px 10px; background: var(--surface); border-bottom: 1px solid var(--hairline); }
.sms-mock-to { display: flex; align-items: center; gap: 7px; padding: 9px 11px; background: var(--surface); border-bottom: 1px solid var(--hairline); font-size: 12px; }
.sms-mock-to-label { color: var(--text-mute); }
.sms-mock-chip { display: inline-flex; align-items: center; font-size: 12px; font-weight: 600; padding: 3px 10px; border-radius: 999px; background: var(--brand-tint); color: var(--brand-text); }
.sms-mock-space { height: 54px; }
.sms-mock-compose { display: flex; align-items: center; gap: 7px; padding: 8px 9px; }
.sms-mock-field { flex: 1; min-width: 0; font-size: 12px; color: var(--text-mute); background: var(--surface); border: 1px solid var(--border); border-radius: 999px; padding: 6px 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sms-mock-field.is-text { color: var(--text); font-weight: 600; letter-spacing: .02em; }
.sms-mock-send { flex: none; width: 26px; height: 26px; border-radius: 999px; background: var(--border); color: #fff; display: inline-flex; align-items: center; justify-content: center; font-size: 13px; line-height: 1; }
.sms-mock-send.is-on { background: var(--brand); color: var(--on-brand); }
.sms-mock-home { width: 62px; height: 4px; border-radius: 3px; background: var(--border); margin: 9px auto 3px; }
.sms-mock .is-focus { box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 22%, transparent); }

/* ---- Notices ---- */
.notice { display: flex; align-items: center; gap: 10px; border-radius: var(--radius); padding: 10px 14px; margin-bottom: 16px; font-size: 13px; }
.notice-warning { background: var(--warn-bg); border: 1px solid var(--warn-border); color: var(--warn-text); }
.notice-warning .notice-action { margin-left: auto; background: var(--warn-accent); color: #fff; padding: 5px 11px; border-radius: var(--radius-sm); font-weight: 600; font-size: 12px; text-decoration: none; }
.notice-error { background: var(--danger-bg); border: 1px solid var(--danger-border); color: var(--danger-text); }
.notice-error .notice-action { margin-left: auto; background: var(--danger-accent); color: #fff; padding: 5px 11px; border-radius: var(--radius-sm); font-weight: 600; font-size: 12px; text-decoration: none; }
/* Inline system messages (override default.css's garish bright red/green) */
.ErrorLabel { color: var(--danger-accent); font-weight: 600; }
.OkLabel { color: var(--brand-text); font-weight: 600; }

/* ---- Responsive (desktop-first, mobile-tolerant) ---- */
@media (max-width: 760px) {
  .app-shell { grid-template-columns: 1fr; }
  .app-sidebar { border-right: none; border-bottom: 1px solid var(--border); position: static; height: auto; overflow: visible; }
  .app-nav { display: flex; flex-wrap: wrap; gap: 4px; }
  .nav-section { width: 100%; }
}
