/* Railfan Radar shared UI components (DESIGN_STANDARDS.md 5.1).
   Load right after /tokens.css. Exactly 5 button types and 2 sizes live here, once,
   for every page. Page styles may add layout to a button (width, flex, margins,
   grid placement) but never color, size, radius, font or shadow. */

/* V121: the status bar's height in the installed app (contentInset
   "never", from app build 3), 0 in a browser. Old builds inset the page
   themselves (the pages add .native-inset for them). */
:root { --safe-top: env(safe-area-inset-top, 0px); }
:root.native-inset { --safe-top: 0px; }

/* ---- Buttons: base = Secondary, Standard size (36px) ---- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  box-sizing: border-box;
  height: var(--h-btn);
  margin: 0;
  padding: 0 var(--sp-4);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font-display);
  font-size: var(--fs-ui);
  font-weight: var(--fw-bold);
  line-height: 1;
  letter-spacing: 0;
  text-transform: none;
  text-decoration: none;
  white-space: nowrap;
  box-shadow: none;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}
/* .btn's display would otherwise override the hidden attribute. */
.btn[hidden] { display: none; }
.btn:hover { background: var(--surface-2); }
.btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.btn .ui-icon { width: var(--icon-md); height: var(--icon-md); }
.btn .ui-icon.lead, .btn .ui-icon.trail { margin: 0; }

/* Compact (28px): dense rows only (roster rows, sighting cards, inline edit actions) */
.btn-compact { height: var(--h-btn-compact); padding: 0 var(--sp-3); font-size: var(--fs-meta); }
.btn-compact .ui-icon { width: var(--icon-sm); height: var(--icon-sm); }

/* Primary: the single main action in a view. --cta for app actions,
   .btn-rr for railroad content (1.2). */
.btn-primary { background: var(--cta); border-color: transparent; color: var(--cta-ink); }
.btn-primary:hover { background: color-mix(in srgb, var(--cta) 92%, black); }
.btn-primary.btn-rr { background: var(--rr); color: var(--rr-ink); }
.btn-primary.btn-rr:hover { background: color-mix(in srgb, var(--rr) 92%, black); }

/* Ghost: cancel, low-emphasis and inline actions */
.btn-ghost { background: transparent; border-color: transparent; color: var(--ink-soft); }
.btn-ghost:hover { background: var(--surface-2); }

/* Danger: delete, reject, destructive confirms */
.btn-danger { background: var(--bad-fill); border-color: transparent; color: var(--cta-ink); }
.btn-danger:hover { background: color-mix(in srgb, var(--bad-fill) 92%, black); }

/* Icon: square, icon-only (needs aria-label); pressed/open = --cta fill */
.btn-icon { width: var(--h-btn); padding: 0; color: var(--ink-soft); }
.btn-icon.btn-compact { width: var(--h-btn-compact); }
/* A Primary icon button (the card's missing-data "+", §5.9) keeps the CTA ink. */
.btn-icon.btn-primary { color: var(--cta-ink); }
.btn-icon[aria-pressed="true"], .btn-icon.active, .btn-icon[aria-expanded="true"] {
  background: var(--cta); border-color: transparent; color: var(--cta-ink);
}
/* Close-X buttons are the one button allowed to be a circle (3.1) */
.btn-close { border-radius: var(--radius-round); }

/* Railroad-content option toggles (direction, track class): selected = --rr fill (1.2) */
.btn-rr-toggle.active { background: var(--rr); border-color: transparent; color: var(--rr-ink); }

/* Layout helper: a full-width button (form submits) */
.btn-block { width: 100%; }

/* Text links are not buttons. A <button> that behaves as a link looks like one (5.1). */
.link-btn {
  display: inline; margin: 0; padding: 0; border: 0; background: none;
  font-family: var(--font-body); font-size: inherit; font-weight: inherit;
  color: var(--cta-text); text-decoration: none; cursor: pointer;
}
.link-btn:hover { text-decoration: underline; }
.link-btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* A text link with an icon keeps the icon and label on one line, 8px apart (4.1) */
a:has(> .ui-icon) { display: inline-flex; align-items: center; gap: var(--sp-2); white-space: nowrap; }
a:has(> .ui-icon) > .ui-icon { margin: 0; }

/* ---- Shared app launcher (5.3; markup from /js/core/app-launcher.js) ---- */
.app-launcher { position: relative; }
.app-launcher-btn svg { width: var(--icon-md); height: var(--icon-md); }
.app-launcher-menu{position:absolute;right:0;top:calc(100% + 9px);z-index:2147483647;width:245px;padding:var(--sp-2);background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow-2);}
.app-launcher-menu[hidden]{display:none;}
.app-launcher-option{display:grid;grid-template-columns:38px 1fr;gap:var(--sp-3);align-items:center;width:100%;padding:var(--sp-3);border:1px solid transparent;border-radius:var(--radius);background:transparent;color:var(--ink);text-align:left;}
.app-launcher-option:hover,.app-launcher-option.active{background:var(--surface-2);}
.app-launcher-option.active{border-color:var(--cta-text);}
.app-launcher-option svg{width:24px;height:24px;color:var(--rr-text, var(--cta-text));}
.app-launcher-option strong{display:block;font-family:var(--font-display);font-size:var(--fs-ui);}
.app-launcher-option small{display:block;color:var(--ink-soft);font-size:var(--fs-micro);margin-top:0;}

/* ---- Toast: a short status that fades by itself (e.g. "Updated 5 segments") ---- */
.toast {
  position: fixed; left: 50%; bottom: calc(var(--sp-6) + env(safe-area-inset-bottom)); z-index: 2000; transform: translateX(-50%);
  max-width: calc(100vw - var(--sp-6)); padding: var(--sp-2) var(--sp-3); border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--good-bg); color: var(--good); box-shadow: var(--shadow-2);
  font-family: var(--font-body); font-size: var(--fs-ui); font-weight: var(--fw-semibold);
}
.toast[hidden] { display: none; }

/* ---- Info cards (5.9; markup from /js/core/infocard.js) ----
   One card for every map feature: photo hero, sticky header, then the
   sections in a fixed order. Exactly two row styles: short (label column +
   value) and long (label line + full-width text). */
.info-card { display: block; color: var(--ink); background: var(--surface); font-family: var(--font-body); }
.info-card [hidden] { display: none !important; }

/* 1. Photo hero, with its credit under it */
.ic-hero { margin: 0 0 var(--sp-3); }
.ic-hero .detail-hero {
  position: relative; display: flex; align-items: center; justify-content: center;
  width: 100%; height: auto; aspect-ratio: 16 / 9; margin: 0; overflow: hidden;
  border-radius: var(--radius); background: var(--surface-2); color: var(--ink);
}
.ic-hero .detail-hero:not(.has-photo) { aspect-ratio: auto; height: 72px; border: 1px dashed var(--line); background: var(--surface); }
.ic-hero .detail-hero img { display: block; width: 100%; height: 100%; object-fit: cover; }
.ic-hero .detail-hero:has(img):after { content: none; }
.ic-hero .detail-photo-credit {
  display: block; margin: var(--sp-1) 0 0; font-size: var(--fs-micro); line-height: 1.4;
  color: var(--ink-soft); text-align: right; white-space: normal; overflow-wrap: anywhere;
}

/* 2. Header: eyebrow, badge + name. No close X: the panel's caret is the
   only close. Sticky while the card scrolls. */
.ic-header {
  position: sticky; top: 0; z-index: 3; display: grid; grid-template-columns: minmax(0, 1fr);
  column-gap: var(--sp-2); align-items: start; margin: 0; padding: var(--sp-2) 0;
  background: var(--surface);
}
.ic-eyebrow.eyebrow { grid-column: 1; margin: 0 0 var(--sp-1); display: block; }
/* The badge sits inline at the start of the name, so a long name wraps
   under it at full width instead of squeezing beside it. */
.ic-title.title-line {
  grid-column: 1; display: block; margin: 0; min-width: 0;
  font-family: var(--font-display); font-size: var(--fs-panel-title); font-weight: var(--fw-bold); line-height: 1.3; color: var(--ink);
}
.ic-title .panel-title { display: inline; margin: 0; font: inherit; color: inherit; overflow-wrap: break-word; }
.ic-title .rr-chip { display: inline-flex; margin: 0 var(--sp-2) 0 0; vertical-align: 3px; }

/* 3–10. Sections: a small-label strip tinted with the owner's color
   (--card-tint, set on the card root by RailfanRailroads.cardTint; neutral
   --surface-2 without one), --ink text, rows split by 1px --line */
.ic-section { margin: var(--sp-3) 0 0; }
.ic-section-title {
  margin: 0; padding: var(--sp-1) var(--sp-3); border-radius: var(--radius); background: var(--card-tint, var(--surface-2));
  font-family: var(--font-body); font-size: var(--fs-micro); font-weight: var(--fw-semibold);
  letter-spacing: var(--label-tracking); text-transform: uppercase; color: var(--ink);
}
/* A divider above every visible row after the first (hidden rows don't count) */
.ic-section > :is(.ic-row, .ic-channel):not([hidden]) ~ :is(.ic-row, .ic-channel, .ic-note) { border-top: 1px solid var(--line); }
.ic-row { margin: 0; padding: var(--sp-2) var(--sp-3); font-size: var(--fs-ui); line-height: 1.5; color: var(--ink); }
.ic-row > span:first-child, .ic-label {
  font-family: var(--font-body); font-size: var(--fs-micro); font-weight: var(--fw-semibold);
  letter-spacing: var(--label-tracking); text-transform: uppercase; color: var(--ink-soft);
}
.ic-label { min-width: 0; overflow-wrap: break-word; }
.ic-value { min-width: 0; overflow-wrap: anywhere; font-variant-numeric: tabular-nums; }
/* Short row: fixed ~84px label column, value on the same line */
.ic-short { display: grid; grid-template-columns: 84px minmax(0, 1fr); column-gap: var(--sp-2); align-items: baseline; }
.ic-short:has(> .ic-value > .rr-badges) { align-items: center; }
/* Long row: label on its own line, text across the full width, never clipped */
.ic-long { display: block; }
.ic-long > .ic-label { display: block; margin: 0 0 var(--sp-1); }
.ic-long > .ic-value { display: block; white-space: pre-line; }
.ic-value .rr-badges { display: inline-flex; flex-wrap: wrap; gap: var(--sp-1); vertical-align: middle; }
.ic-num { font-weight: var(--fw-bold); }
/* Missing data: "—" and the 28px CTA "+" that opens edit mode on the field */
.ic-value:has(> .ic-missing) { display: flex; align-items: center; gap: var(--sp-2); }
.ic-missing { color: var(--ink-soft); }
.ic-sub { color: var(--ink-soft); font-size: var(--fs-meta); }
.ic-note { margin: 0; padding: var(--sp-2) var(--sp-3); font-size: var(--fs-meta); line-height: 1.5; color: var(--ink-soft); }
.ic-pill {
  display: inline-flex; align-items: center; margin: 0 0 0 var(--sp-1); padding: var(--sp-1) var(--sp-2);
  border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface-2); color: var(--ink);
  font-family: var(--font-body); font-size: var(--fs-meta); font-weight: var(--fw-semibold); line-height: 1; cursor: pointer;
}
/* Editing opens a row's field right where it is, full width */
.ic-row.inline-editing, .ic-section.inline-editing { display: block; }
.ic-row.inline-editing > span:first-child, .ic-section.inline-editing > span:first-child { display: block; margin: 0 0 var(--sp-1); }
.ic-section.inline-editing { padding: var(--sp-2) var(--sp-3); }
.ic-row .inline-edit-control, .ic-section .inline-edit-control { display: flex; flex-wrap: wrap; gap: var(--sp-2); min-width: 0; }
.ic-row .inline-edit-control > input, .ic-row .inline-edit-control > select, .ic-row .inline-edit-control > textarea { flex: 1 1 100%; min-width: 0; }
/* Edit-mode controls (§5.5): 36px, 1px --line, 6px radius, 16px text */
.info-card .inline-edit-control :is(input:not([type=hidden]):not([type=checkbox]):not([type=radio]), select, textarea) {
  box-sizing: border-box; min-height: var(--h-btn); margin: 0; padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); color: var(--ink);
  font-family: var(--font-body); font-size: var(--fs-input); line-height: 1.25;
}
.info-card .inline-edit-control :is(input:not([type=hidden]):not([type=checkbox]):not([type=radio]), select) { height: var(--h-btn); padding-top: 0; padding-bottom: 0; }
.info-card .inline-edit-control textarea { resize: vertical; overflow: hidden; }
.info-card .inline-edit-control :is(input, select, textarea):focus { outline: none; border-color: var(--cta-text); box-shadow: var(--focus-ring); }
/* Edit mode: the action bar (and its Delete) steps aside for the sticky
   Save / Cancel bar; the map-data provenance rows aren't edited here. */
.info-card.ic-editing :is(.card-actions-row, .ic-staff-actions, .loco-history-actions, .companion-actions),
.info-card.ic-moving :is(.card-actions-row, .ic-staff-actions, .loco-history-actions, .companion-actions),
.info-card.ic-editing [data-ic-field="osm_source"],
.info-card.ic-editing[data-card-type="subdivision"] :is([data-ic-field="owner"], [data-ic-field="ref"]) { display: none; }
/* Sticky only sticks within its parent: while editing (or moving) the
   actions box steps out of layout, so the Save / Cancel bar sticks to the
   bottom of the whole card as it scrolls. */
.info-card:is(.ic-editing, .ic-moving) > .ic-actions { display: contents; }
/* Owner picker: the railroad's badge, a box to change it, remove */
.rr-picker { display: flex; align-items: center; gap: var(--sp-2); width: 100%; min-width: 0; }
.rr-picker-badge { flex: none; display: inline-flex; align-items: center; min-width: 56px; }
.info-card .rr-picker > input { flex: 1 1 auto; min-width: 0; }
/* Other railroads: removable badge chips, then a box and "+" */
.rr-list { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.rr-list-chip { display: inline-flex; align-items: center; gap: var(--sp-1); padding: 0 0 0 var(--sp-1); border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); }
.rr-list-add { display: flex; align-items: center; gap: var(--sp-2); }
.info-card .rr-list-add > input { flex: 1 1 auto; min-width: 0; }
/* Coordinates: one field and its "Move on map" icon button */
.coords-edit { display: flex; align-items: center; gap: var(--sp-2); width: 100%; min-width: 0; }
.info-card .coords-edit > input { flex: 1 1 auto; min-width: 0; font-variant-numeric: tabular-nums; }
/* Channel rows: drag handle and trash */
.row-drag { cursor: grab; touch-action: none; }
.row-drag:active { cursor: grabbing; }
.is-dragging { background: var(--surface-2); }

/* 4. Radio channel rows: badge · "Type · note" over its secondary line · "Ch 18" over "160.380 MHz" */
.ic-channel { position: relative; padding: var(--sp-2) var(--sp-3); font-size: var(--fs-ui); line-height: 1.5; }
.ic-ch-full { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; column-gap: var(--sp-2); align-items: start; }
.ic-ch-badge { min-width: 56px; }
.ic-ch-badge:empty { display: none; }
.ic-ch-badge:empty + .ic-ch-main { grid-column: 1 / span 2; }
.ic-ch-main { display: flex; flex-direction: column; min-width: 0; }
.ic-ch-title { color: var(--ink); overflow-wrap: anywhere; }
.ic-ch-detail { color: var(--ink-soft); font-size: var(--fs-micro); }
.ic-ch-freq { display: flex; flex-direction: column; align-items: flex-end; text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.ic-ch-freq b { font-weight: var(--fw-bold); }
.ic-ch-freq span { color: var(--ink-soft); font-size: var(--fs-micro); }
.ic-ch-mini { display: none; }
/* Minimized: "Road · north end" gives way first; "Ch 18 · 160.380" always shows. */
.ic-ch-mini .ic-value { display: flex; align-items: baseline; gap: var(--sp-1); min-width: 0; white-space: nowrap; }
.ic-mini-type { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.ic-mini-ch { flex: none; font-variant-numeric: tabular-nums; }
.ic-mini-typelabel, .ic-mini-tight .ic-mini-radio, .ic-mini-tight .ic-mini-type { display: none; }
.ic-mini-tight .ic-mini-typelabel { display: inline; }
.ic-ch-mini .ic-pill { flex: none; }

/* 11. Actions: ONE row, Edit · Move · Directions · Share ··· Delete (staff
   only, far right). When it doesn't fit, Directions and Share drop to
   icon-only first, then Move (fitActionRow in map.js sets the classes).
   Staff-only extra tools (Restore OSM data, Merge, Reassign) sit in their
   own row under it. */
.ic-actions { display: flex; flex-direction: column; gap: var(--sp-2); margin: var(--sp-4) 0 0; }
.ic-action-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.ic-action-row:empty { display: none; }
.ic-action-row > #cardEditActions:empty { display: none; }
#cardActionsRow { flex-wrap: nowrap; align-items: center; min-width: 0; }
#cardActionsRow > * { flex: none; }
#cardActionsRow > #cardDangerActions { margin-left: auto; display: flex; gap: var(--sp-2); }
#cardActionsRow > #cardDangerActions:empty { display: none; }
#cardActionsRow.ic-icons-1 :is(#cardDirectionsBtn, #cardShareBtn) .btn-label,
#cardActionsRow.ic-icons-2 :is(#cardDirectionsBtn, #cardShareBtn, #modMoveBtn) .btn-label { display: none; }
#cardActionsRow.ic-icons-1 :is(#cardDirectionsBtn, #cardShareBtn) .ui-icon.lead,
#cardActionsRow.ic-icons-2 :is(#cardDirectionsBtn, #cardShareBtn, #modMoveBtn) .ui-icon.lead { margin: 0; }
#cardActionsRow.ic-icons-1 :is(#cardDirectionsBtn, #cardShareBtn),
#cardActionsRow.ic-icons-2 :is(#cardDirectionsBtn, #cardShareBtn, #modMoveBtn) { width: var(--h-btn-compact); padding: 0; justify-content: center; }

/* Toast variants (V26): the warning tint (§1.3) and an action button; with
   an action the toast stays until tapped. */
.toast { display: flex; align-items: center; gap: var(--sp-3); }
.toast-warn { background: var(--warn-bg); color: var(--warn); border-color: color-mix(in srgb, var(--warn) 35%, transparent); }
.toast .toast-action { flex: none; }

/* ?diag=1 diagnostics log (V26): a §5.4 panel above the map. */
.diag-panel {
  position: fixed; left: var(--sp-4); right: var(--sp-4); bottom: calc(var(--sp-6) + env(safe-area-inset-bottom)); z-index: 2100;
  max-height: 60vh; display: flex; flex-direction: column; gap: var(--sp-2);
  padding: var(--sp-2); border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); box-shadow: var(--shadow-2);
}
.diag-head { display: flex; align-items: center; gap: var(--sp-2); }
.diag-head .eyebrow { flex: 1; }
.diag-log { margin: 0; overflow: auto; white-space: pre-wrap; word-break: break-word; font-family: var(--font-body); font-size: var(--fs-micro); color: var(--ink); }

/* V49: a signal card's "On the same structure" (DESIGN_STANDARDS 5.6 chips). */
.structure-group{margin-top:var(--sp-3);}
.structure-group-row{display:flex;flex-wrap:wrap;gap:var(--sp-2);align-items:center;margin:var(--sp-2) 0;}
.structure-member{display:inline-flex;align-items:center;gap:var(--sp-1);padding:var(--sp-1) var(--sp-2);border:1px solid var(--line);border-radius:var(--radius);background:var(--surface);font-family:var(--font-body);font-size:var(--fs-meta);font-weight:600;color:var(--ink);}
.structure-member .btn{height:auto;min-height:0;padding:0;}
.structure-member.is-removed{opacity:.5;text-decoration:line-through;}
.structure-signal-link{display:inline;height:auto;min-height:0;padding:0;vertical-align:baseline;}
#structureSource{width:100%;margin-top:var(--sp-2);}
.cantilever-base-set{display:flex;flex-wrap:wrap;gap:var(--sp-2);margin-top:var(--sp-2);}
.ic-row[hidden]{display:none!important;}

/* Direction grid (Faces, and V69 the cantilever base): 8 compass buttons,
   a strip of 4x2 or, with .direction-compass, a compass rose. Moved from
   map-gl.html unchanged. */
.direction-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--sp-2);}
.direction-btn-invalid,.direction-btn:disabled{opacity:.3;cursor:not-allowed;}
.direction-btn-invalid.active,.direction-btn:disabled.active{background:var(--surface);border-color:var(--line);color:var(--ink);}
/* The compass-rose variant lays the same 8 buttons out as an actual
   compass instead of the 4x2 strip above — N/S/E/W on the cardinal edges,
   the four combined directions in the corners, the real signal icon
   (colored to match its railroad, same as the one already on the map —
   see editDirectionGridHtml) sitting in the open center cell — inside a
   fixed 128x128 square. Used by the mobile pin-confirm bar (which also
   needs the [hidden]-vs-author-style fix below) and the "Edit directly"
   signal form, on any viewport. directionGridHtml() always emits the 8
   buttons in the same N,NE,E,SE,S,SW,W,NW order, so each is placed by its
   position in that sequence rather than by data-direction, which keeps
   this purely a CSS override with no JS/markup duplication. */
.direction-grid.direction-compass:not([hidden]){display:grid;grid-template-columns:repeat(3,1fr);grid-template-rows:repeat(3,1fr);width:128px;height:128px;gap:var(--sp-1);}
.direction-grid.direction-compass .direction-btn{padding:0;font-size:var(--fs-meta);}
.direction-grid.direction-compass .direction-btn:nth-child(1){grid-column:2;grid-row:1;} /* N */
.direction-grid.direction-compass .direction-btn:nth-child(2){grid-column:3;grid-row:1;} /* NE */
.direction-grid.direction-compass .direction-btn:nth-child(3){grid-column:3;grid-row:2;} /* E */
.direction-grid.direction-compass .direction-btn:nth-child(4){grid-column:3;grid-row:3;} /* SE */
.direction-grid.direction-compass .direction-btn:nth-child(5){grid-column:2;grid-row:3;} /* S */
.direction-grid.direction-compass .direction-btn:nth-child(6){grid-column:1;grid-row:3;} /* SW */
.direction-grid.direction-compass .direction-btn:nth-child(7){grid-column:1;grid-row:2;} /* W */
.direction-grid.direction-compass .direction-btn:nth-child(8){grid-column:1;grid-row:1;} /* NW */
.direction-grid-preview{grid-column:2;grid-row:2;display:flex;align-items:center;justify-content:center;}
.direction-grid-preview .signal-symbol{display:block}
.direction-grid-message{margin:var(--sp-2) 0 0;font-size:var(--fs-meta);color:var(--ink-soft)}

/* ---- Data use (V81): reports waiting on this phone ----
   One panel (public/js/core/dataMode.js) on the map and the Account page:
   §5.7-style list rows with compact buttons. Low data mode itself is the
   toolbar's signal button (V108). */
.outbox-heading { margin: var(--sp-4) 0 var(--sp-2); font-family: var(--font-body); font-size: var(--fs-micro); font-weight: var(--fw-semibold); letter-spacing: var(--label-tracking); text-transform: uppercase; color: var(--ink-soft); }
.outbox-heading:first-child { margin-top: 0; }
.outbox-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.outbox-row { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--sp-2) var(--sp-2); padding: var(--sp-2) var(--sp-3); border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); }
.outbox-row.is-focus { border-color: var(--cta-text); }
.outbox-icon { line-height: 0; }
.outbox-icon.is-pending, .outbox-text small.is-pending { color: var(--pending); }
.outbox-icon.is-bad, .outbox-text small.is-bad { color: var(--bad); }
.outbox-text { min-width: 0; font-family: var(--font-body); }
.outbox-text strong { display: block; font-size: var(--fs-ui); font-weight: var(--fw-semibold); color: var(--ink); overflow-wrap: anywhere; }
.outbox-text small { display: block; margin-top: var(--sp-1); font-size: var(--fs-meta); line-height: 1.4; }
.outbox-actions { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.outbox-empty { font-family: var(--font-body); font-size: var(--fs-meta); color: var(--ink-soft); }
.outbox-message { margin-top: var(--sp-2); font-family: var(--font-body); font-size: var(--fs-meta); }
.outbox-message:empty { display: none; }
.outbox-message.error { color: var(--bad); }
.outbox-message.success { color: var(--good); font-weight: var(--fw-bold); }
/* A list photo held back in Low data mode: the thumbnail's own box, with
   an outline image icon. */
.photo-deferred { display: inline-flex; align-items: center; justify-content: center; color: var(--ink-soft); background: var(--surface-2); border: 1px solid var(--line); box-sizing: border-box; }

/* ---- V116: shared tooltip, skeleton loaders, inline load error ----
   Tooltip: one component (js/core/tooltip.js) for every icon-only button,
   on hover, keyboard focus and long-press. */
.ui-tooltip {
  position: fixed; z-index: 2100; max-width: 240px; padding: var(--sp-1) var(--sp-2);
  border-radius: var(--radius); background: var(--ink); color: var(--bg); box-shadow: var(--shadow-2);
  font-family: var(--font-body); font-size: var(--fs-meta); font-weight: var(--fw-semibold); line-height: 1.3;
  pointer-events: none;
}
.ui-tooltip[hidden] { display: none; }
/* Skeleton: gray shapes in the layout of what's loading, a soft pulse
   (none under reduced motion). */
.skeleton { display: flex; flex-direction: column; gap: var(--sp-3); }
.skeleton-row { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) 0; border-bottom: 1px solid var(--line); }
.skeleton-lines { flex: 1; display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }
.sk { display: block; height: 12px; border-radius: var(--radius); background: var(--surface-2); animation: sk-pulse 1.4s ease-in-out infinite; }
.sk-title { width: 45%; height: 14px; }
.sk-meta { width: 70%; }
.sk-short { width: 30%; }
.sk-btn { flex: none; width: 96px; height: var(--h-btn-compact); }
.sk-input { flex: none; width: 180px; height: var(--h-btn-compact); }
.sk-block { width: 100%; height: 120px; }
@keyframes sk-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }
@media (prefers-reduced-motion: reduce) { .sk { animation: none; } }
/* A request that failed: what went wrong and Retry, in place of the list. */
.load-error { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); padding: var(--sp-3); border: 1px solid color-mix(in srgb, var(--bad) 35%, transparent); border-radius: var(--radius); background: var(--bad-bg); color: var(--bad); font-size: var(--fs-ui); }
.load-error span { flex: 1; min-width: 200px; }
.toast-bad { background: var(--bad-bg); color: var(--bad); border-color: color-mix(in srgb, var(--bad) 35%, transparent); }
