/* app/set-comms.css — page-local styles for Accounts + Calls.
   Prefix every selector `.e8-set-comms-`. Shared grammar lives in app/set-core.css and must not
   be duplicated here; if a page needs a new shared primitive, that is a core change, not a
   local override. Tokens only — no hex, no raw font sizes.

   WHAT IS HERE, AND WHY IT IS NOT IN CORE
   Only four shapes, each specific to one page and none of them a row, card or control:
     1. the connect-tile pair on Accounts (§Email and Calendar) — a two-up grid of bordered
        blocks that sits BETWEEN the section description and the card, so it is not a card row,
        carrying a monochrome brand mark apiece;
     2. one flex line INSIDE a core Banner, so the connected-account sentence and its Disconnect
        sit on one row — the banner is the primitive, this is only how its children queue up;
     3. the JPEG picker that appears under the Custom avatar radio on Calls;
     4. two tone tweaks — the messaging row's green mark, and an inline link inside a banner.
   Everything else on both pages is a core primitive with no local CSS at all.

   DIMENSIONS ARE BORROWED, NEVER RE-CHOSEN. Colours, hairlines and radii read the same
   `--set-*` / `--ui-*` variables core uses, so a retune in core moves these with it. The literal
   pixel gaps are copied from the core rule they sit beside — the picker's 34px control height and
   13px side padding are `.e8-set-btn`'s, the 14px block gap is `.e8-set-card + .e8-set-card`'s —
   which is why they are spelled the same way core spells them rather than swapped to
   `--ui-space-*`. Half a file on tokens and half on core's literals is how a page drifts a pixel
   away from its neighbours; matching the sibling grammar exactly is the point. */

/* ---------- Accounts · connect tiles ---------------------------------------------------------- */
/* minmax(0, 1fr), not 1fr: a bare 1fr floors at min-content, so a long provider name would push
   the track wider than half and the two tiles would stop being equal.

   12px below, matching `.e8-set-banner`'s own margin-bottom, so the two gaps this block now creates
   — tiles to banner, banner to card — are the same number. The wrapper that used to hold the tiles
   and the note together is gone: the note is a core Banner now and carries its own spacing. */
.e8-set-comms-connectgrid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px;
  margin-bottom: 12px;
}
.e8-set-comms-connect {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  min-height: 48px; padding: 0 14px; width: 100%;
  border: 1px solid var(--set-line); border-radius: var(--set-radius-card);
  background: var(--ui-surface); color: var(--ui-text);
  font: inherit; font-size: var(--ui-text-base); font-weight: 500;
  cursor: pointer; text-align: center;
  transition: border-color 120ms ease, background 120ms ease;
}
.e8-set-comms-connect:hover { background: var(--ui-fill); border-color: var(--ui-border-strong); }
.e8-set-comms-connect.is-on { border-color: var(--ui-accent); box-shadow: inset 0 0 0 1px var(--ui-accent); }
/* Only the tile that is NOT connected is ever disabled — the connected one stays a live toggle, so
   there is deliberately no `.is-on:disabled` rule here; it could never match.

   Both of these sit AFTER `:hover` rather than raising their own specificity. Engines disagree on
   whether `:hover` matches a disabled control (hit-testing on disabled form controls is suppressed
   in some and not others), so rather than depend on the answer, the later equal-specificity rule
   settles it the same way everywhere. Folding `:not(:disabled)` into the `:hover` selector instead
   would take it to three classes and it would start beating `.is-on`'s accent border on hover —
   fixing the dim by breaking the connected state. 0.42 is core's own `is-locked` / `:disabled`
   dim, not a new number. */
.e8-set-comms-connect:disabled { opacity: 0.42; cursor: not-allowed; }
.e8-set-comms-connect:disabled:hover { background: var(--ui-surface); border-color: var(--set-line); }
.e8-set-comms-connect-t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.e8-set-comms-connect-ok { font-size: var(--ui-icon-sm); color: var(--ui-accent); flex: none; }

/* The provider mark: brand GEOMETRY, monochrome, on the category tints. The brand colours
   themselves are not available to us — they are neither `--ui-*` tokens nor invertible, and a raw
   hex is a lint failure here and a dark-mode bug everywhere — but the shape is what tells the two
   48px blocks apart, and a letter in a box tells you nothing. `fill: currentcolor` puts the mark on
   the same tint pair the box uses, so it inverts with the theme for free. */
.e8-set-comms-mark {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: var(--ui-radius);
}
.e8-set-comms-mark.is-a { background: var(--ui-cat-2-bg); color: var(--ui-cat-2-text); }
.e8-set-comms-mark.is-b { background: var(--ui-cat-1-bg); color: var(--ui-cat-1-text); }
/* Sized here rather than with width/height attributes so the two marks cannot drift apart, and
   because 15px inside a 26px box is a padding decision, not a property of the artwork. */
.e8-set-comms-marksvg { width: 15px; height: 15px; display: block; fill: currentcolor; }

/* The connected banner's one line: the status sentence, and the disconnect that acts on it. Wraps
   at every width rather than at a breakpoint — the sentence carries a provider name and a persona
   name, so the width it stops fitting at is data, not a number we can pick. */
.e8-set-comms-noteline {
  display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap;
  gap: 8px 12px; width: 100%;
}

/* ---------- Accounts · messaging mark --------------------------------------------------------- */
/* Scoped to the one row rather than given a core tone, because a green glyph box means "a live
   channel" on this page only. A `tone` on SetGlyph would be a core change with one caller.

   `color` is set on the BOX, not only on the glyph inside it. The box previously carried a green
   fill and a green border around ink that computed to primary — the tint stopped at the border and
   the mark inside read as one of the four neutral glyphs above it, which is what half-tinting looks
   like: an accident. Declaring it on the container also makes the element's own computed `color`
   green, so the box and its glyph answer the same question the same way however they are measured.
   The inner rule stays because it has to: core's `.e8-set-glyph .material-symbols-outlined` sets
   `--ui-icon-quiet` directly on the glyph, and an inherited colour never beats a declared one. */
.e8-set-comms-row-msg .e8-set-glyph {
  background: color-mix(in srgb, var(--ui-success) 14%, transparent);
  border-color: color-mix(in srgb, var(--ui-success) 30%, transparent);
  color: var(--ui-success);
}
.e8-set-comms-row-msg .e8-set-glyph .material-symbols-outlined { color: var(--ui-success); }

/* ---------- Calls · inline link inside a banner ----------------------------------------------- */
.e8-set-comms-blink {
  border: 0; background: transparent; padding: 0; cursor: pointer;
  font: inherit; font-size: inherit; font-weight: 500; color: var(--ui-accent);
  text-decoration: underline; text-underline-offset: 2px;
}
.e8-set-comms-blink:hover { color: var(--ui-accent-hover); }

/* ---------- Calls · stacked field inside a row ------------------------------------------------
   SetRow renders `children` under the description, inside the label column. That is the
   reference's stacked-field shape (the recorder-name input runs nearly the full card width), so
   the only thing needed here is the gap between the description and what follows it. */
.e8-set-comms-field .e8-set-input,
.e8-set-comms-radios { margin-top: 10px; }

/* ---------- Calls · avatar upload -------------------------------------------------------------- */
.e8-set-comms-upload { display: flex; align-items: center; gap: 12px; margin-top: 12px; }
/* 16:9 at the smallest size that still reads as a preview of a 1280x720 image. */
.e8-set-comms-thumb {
  flex: none; width: 96px; height: 54px; border-radius: var(--set-radius-ctl);
  border: 1px solid var(--set-line); background: var(--ui-fill);
  background-image: var(--e8-sc-avatar, none); background-size: cover; background-position: center;
  display: inline-flex; align-items: center; justify-content: center;
}
.e8-set-comms-thumb.is-empty .material-symbols-outlined {
  font-size: var(--ui-icon-md); color: var(--ui-text-tertiary);
}
.e8-set-comms-uploadtxt { display: flex; flex-direction: column; align-items: flex-start; gap: 5px; min-width: 0; }

/* The input stays in the tab order and keeps its own focus, which is then DRAWN on the label —
   `display: none` or `visibility: hidden` would make the control keyboard-unreachable, and a
   click-only file picker is the commonest way this pattern ships broken. */
.e8-set-comms-uploadtxt input[type="file"] {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}
.e8-set-comms-uploadtxt label {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  height: 34px; padding: 0 13px; border-radius: var(--set-radius-ctl);
  border: 1px solid var(--set-line); background: var(--ui-surface); color: var(--ui-text);
  font-size: var(--ui-text-base); font-weight: 500; cursor: pointer; white-space: nowrap;
}
.e8-set-comms-uploadtxt label:hover { background: var(--ui-fill); }
.e8-set-comms-uploadtxt label .material-symbols-outlined { font-size: var(--ui-icon-sm); }
.e8-set-comms-uploadtxt input[type="file"]:focus-visible + label {
  outline: none; box-shadow: var(--ui-focus-ring);
}
.e8-set-comms-uploadname {
  font-size: var(--ui-text-sm); color: var(--ui-text-secondary);
  overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}
.e8-set-comms-err { font-size: var(--ui-text-sm); color: var(--ui-danger); line-height: 1.45; }

/* ---------- narrow --------------------------------------------------------------------------
   AFTER every rule each one overrides. A conditional at-rule adds no specificity, so a @media
   written above its own base rule can never win — dead code that errors nowhere.

   ONE breakpoint, not two, and 840 is deliberately absent. 840 is where the rail becomes a drawer,
   so the content column gets WIDER as it is crossed (≈600px of column at 841, ≈810px at 839) —
   an override there would relax the layout at the moment it stops being tight. Nothing on either
   page needs a change until the two connect tiles stop fitting side by side, which is 640. */
@media (max-width: 640px) {
  .e8-set-comms-connectgrid { grid-template-columns: minmax(0, 1fr); }
  /* The connected note needs no entry here any more. It was a bespoke flex line that had to be
     told to wrap at 640; it is a core Banner now, and `.e8-set-comms-noteline` wraps on content at
     every width, so there is nothing left for a breakpoint to correct. */
  .e8-set-comms-upload { flex-direction: column; align-items: flex-start; }
  /* Capped: a full-column 16:9 preview at 390px is 220px tall and dwarfs the card it sits in. */
  .e8-set-comms-thumb { width: 100%; max-width: 240px; height: auto; aspect-ratio: 16 / 9; }
  .e8-set-comms-uploadtxt { width: 100%; }
}
