/* ============================================================================
   Mobile / touch layer — the design-system's coarse-pointer foundation.

   Imported LAST in application.tailwind.css (after the component/shell/tiptap
   layers) so these rules win the cascade on touch devices with no per-component
   override. Everything here is unlayered, so it also beats Tailwind's layered
   utilities (e.g. an inline `text-[14px]`) on the same element.

   Token-only — values live in _design_tokens.css. Fixes, once and app-wide:
   sub-44px hit areas, iOS Safari zoom-on-focus (fields < 16px), the native
   tap-highlight flash, and OS text auto-inflation. Desktop (pointer:fine) and
   headless system-test browsers are unaffected — every sizing rule is gated on
   @media (pointer: coarse), which does not match a mouse/trackpad primary.
   ========================================================================== */

/* Remove the native blue/grey tap flash on interactive elements. Harmless on
   desktop (there is no touch highlight to suppress). */
a,
button,
label,
summary,
[role="button"],
.btn,
input,
select,
textarea {
  -webkit-tap-highlight-color: transparent;
}

/* Deterministic text sizing — stop iOS/Android from auto-inflating reflowed
   text and breaking the tuned type scale on rotation. */
html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

@media (pointer: coarse) {
  /* 44px minimum hit area on every interactive control (WCAG 2.5.5 / Apple HIG
     / Material 3). min-height only grows the box, never shrinks a control. */
  .btn,
  .input,
  .select,
  .modal__close,
  .side-panel__close,
  .toast__dismiss,
  .tag__remove,
  .search-input__clear {
    min-height: var(--tap-min);
  }

  /* Icon-only close / dismiss glyphs: also widen and center the glyph inside
     the enlarged hit box so the target grows symmetrically. */
  .modal__close,
  .side-panel__close,
  .toast__dismiss,
  .tag__remove,
  .search-input__clear {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: var(--tap-min);
  }

  /* Kill iOS Safari zoom-on-focus: any focusable text field is >= 16px on touch
     (the WebKit threshold). Desktop keeps its denser 14px. Excludes controls
     whose font-size is irrelevant (checkbox/radio/range/color/file). */
  .input,
  .select,
  textarea,
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]) {
    font-size: 16px;
  }
}

/* Opt-in mobile primitives — consumed by the mail list, reading pane and
   composer surfaces (Waves 3-7). */
.u-scroll-contain {
  overscroll-behavior: contain;
}

.u-wrap-anywhere {
  overflow-wrap: anywhere;
  word-break: break-word;
}

.u-swipeable {
  touch-action: pan-y;
}

/* Mailing: while a thread or composer overlay owns the screen (marked with
   .mail-overlay-content, in both the slide-over frame and the full-page deep
   link), hide the floating mobile chrome (mailbox hamburger + module-switcher
   trigger) so it can't occlude the pane's own Back / Print / close controls.
   Pure CSS (:has), scoped to the phone breakpoint. */
@media (max-width: 767px) {
  body:has(.mail-overlay-content) .mail-float-chrome {
    display: none;
  }
}

/* Mail list-row density metrics applied via classes (the density tokens live
   here, NOT as inline style= attributes — keeps audit 60_inline_styles at 0). */
/* Sender monogram. Size follows the density triplet; the disc colour comes from
   the deterministic per-sender palette (--mail-avatar-N, see _design_tokens.css)
   so it is legible on BOTH themes — the old accent-soft tint dissolved into the
   background on a phone. `--mail-avatar-*` is set on the element by the variant
   class below; the base rule reads it, so there is no inline style= (audit 60). */
.mail-avatar {
  width: var(--mail-avatar-size);
  height: var(--mail-avatar-size);
  background: var(--mail-avatar-bg);
  color: var(--mail-avatar-fg);
  font-size: 13px;
  line-height: 1;
  letter-spacing: 0.02em;
}

.mail-avatar--1 { --mail-avatar-bg: var(--mail-avatar-1); }
.mail-avatar--2 { --mail-avatar-bg: var(--mail-avatar-2); }
.mail-avatar--3 { --mail-avatar-bg: var(--mail-avatar-3); }
.mail-avatar--4 { --mail-avatar-bg: var(--mail-avatar-4); }
.mail-avatar--5 { --mail-avatar-bg: var(--mail-avatar-5); }
.mail-avatar--6 { --mail-avatar-bg: var(--mail-avatar-6); }
.mail-avatar--7 { --mail-avatar-bg: var(--mail-avatar-7); }
.mail-avatar--8 { --mail-avatar-bg: var(--mail-avatar-8); }

/* Reading-pane header monogram — same palette, its own fixed size (the thread
   is not density-driven; the header avatar is a constant 44px). */
.mail-avatar--lg {
  width: 44px;
  height: 44px;
  font-size: 15px;
}

.mail-snippet {
  display: var(--mail-snippet-display);
}

/* The em-dash only separates subject from snippet when they share a line
   (sm+). On a phone the snippet sits on its own line, where a leading dash
   would just be noise — so it lives in CSS, not in the markup. */
@media (min-width: 640px) {
  .mail-snippet::before {
    content: "— ";
  }
}

/* ── Mail row meta column (date + flag) ────────────────────────────────────
   The row's fixed right edge. The date lives in a fixed-width, right-aligned
   slot INSIDE this column and not on the sender's text line, which is what
   makes the column actually line up:
     · on the text line the date rode the first baseline while the flag was
       centred on a two- (or three-) line row — the right edge read as a
       staircase;
     · a paperclip, or any change in the sender's width, shifted the date left
       — so no two rows agreed on where the date column was.
   Now every row's date sits on the same x, on the same centre line as the flag,
   with or without an attachment. */
.mail-row-meta {
  position: relative;
}

.mail-row-date {
  flex: none;
  /* Fixed slot on a wide screen: every snippet then truncates on the SAME x,
     which is what gives the list its vertical rhythm (Gmail / Outlook do this).
     Wide enough for «15.06.2020», the longest form the smart date can take. */
  inline-size: 5.25rem;
  text-align: end;
  white-space: nowrap;
}

/* On a phone that slot would cost the subject 84 of its ~200 usable px, so the
   date sizes to its content instead. Alignment survives: the flag is the last,
   fixed-width item in the column, so every date still ends on the same x — only
   the (invisible) left edge moves. */
@media (max-width: 639px) {
  .mail-row-date {
    inline-size: auto;
  }
}

/* ── Mail row quick actions — CSS-only hover/focus reveal ───────────────────
   Replaces the old Stimulus mouseenter toggle, which was dead on desktop
   (`md:flex` beat `hidden` in the cascade → the cluster showed PERMANENTLY,
   sitting on top of the timestamp: «дат не видно, приходится открывать письмо»)
   and left a stuck block-strip after a tap on touch (the compatibility
   mouseenter fires there too).

   The cluster is ABSOLUTE, pinned to the meta column's leading edge, so it
   unfurls over the snippet's tail and displaces NOTHING: the date and the flag
   keep their exact position whether the cursor is on the row or not. (Laying it
   out in flow was the first attempt — it pushed the date ~100px left the moment
   you hovered, which is the jump that read as «криво».) The date is never
   covered: the cluster stops where the date column begins. */
.mail-row-actions {
  position: absolute;
  inset-inline-end: 100%;
  inset-block: 0;
  z-index: 1;
  display: none;
  align-items: center;
  gap: 1px;
  padding-inline: 0.5rem 0.25rem;
  background: var(--color-bg-elevated);
}

/* Soft fade into the snippet it overlaps — a hard edge would read as a cut. */
.mail-row-actions::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-end: 100%;
  inline-size: 2rem;
  background: linear-gradient(to left, var(--color-bg-elevated), transparent);
  pointer-events: none;
}

/* Keyboard focus lands on a row that is NOT hovered, so give it the same
   elevated surface the cluster paints on — otherwise the cluster would sit as a
   lighter patch on the plain row background. */
.mail-swipe__row:has(:focus-visible) {
  background: var(--color-bg-elevated);
}

/* Reveal on hover, and on keyboard focus inside the row (WCAG 2.1.1 — tabbing
   in brings the buttons into the tab order right after the flag; :focus-visible
   means a tap never triggers it). */
.mail-swipe__row:hover .mail-row-actions,
.mail-swipe__row:has(:focus-visible) .mail-row-actions {
  display: flex;
}

/* Touch: hide it again. Excluding coarse pointers is deliberately the INVERSE
   of an `(hover: hover) and (pointer: fine)` allowlist — headless Chrome (our
   system-test + browser-verification environment) reports `hover: none` AND
   `pointer: none`, so an allowlist would make this reveal untestable and
   unverifiable, exactly the blind spot that let the always-on cluster ship.
   A coarse pointer is a touchscreen by definition; everything else (mouse,
   trackpad, stylus, headless) keeps the hover path. On touch the triage is
   swipe / long-press, and a tap can never leave the strip stuck open. */
@media (pointer: coarse) {
  .mail-swipe__row:hover .mail-row-actions {
    display: none;
  }
}

/* ── Mail row swipe-to-triage (mailing--swipe-row) ──────────────────────────
   The .mail-swipe__row (opaque via a Tailwind bg + relative) slides over the
   reveal panels behind it: right-swipe uncovers Archive (success), left-swipe
   Delete (danger). Panels are md:hidden (touch only), revealed via inline
   opacity written by the controller. */
.mail-swipe__row {
  position: relative;
  z-index: 1;
}

.mail-swipe__row.is-swiping {
  will-change: transform;
  user-select: none;
}

.mail-swipe__reveal {
  position: absolute;
  inset-block: 0;
  z-index: 0;
  display: flex;
  align-items: center;
  inline-size: 45%;
  opacity: 0;
  color: var(--color-accent-on);
}

.mail-swipe__reveal--archive {
  inset-inline-start: 0;
  justify-content: flex-start;
  padding-inline-start: 24px;
  background: var(--color-success);
}

.mail-swipe__reveal--delete {
  inset-inline-end: 0;
  justify-content: flex-end;
  padding-inline-end: 24px;
  background: var(--color-danger);
}

/* ── Undo snackbar — swipe / bulk optimistic actions (built by the controller,
   like the upload chips). Thumb-zone, above the home indicator. ───────────── */
#mailing-undo {
  position: fixed;
  inset-inline: 0;
  bottom: calc(1rem + var(--safe-bottom));
  z-index: var(--z-toast);
  display: flex;
  justify-content: center;
  padding-inline: 1rem;
  pointer-events: none;
}

.mail-undo {
  display: inline-flex;
  align-items: center;
  gap: 1rem;
  max-inline-size: 92vw;
  padding: 0.625rem 0.625rem 0.625rem 1rem;
  border-radius: var(--radius-lg);
  background: var(--color-fg);
  color: var(--color-bg);
  box-shadow: var(--shadow-pop);
  font-size: 0.875rem;
  pointer-events: auto;
}

.mail-undo__text {
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mail-undo__action {
  flex: none;
  min-block-size: var(--tap-min);
  padding-inline: 0.5rem;
  color: var(--color-accent);
  font-weight: 600;
  background: none;
  border: 0;
  cursor: pointer;
}

/* Long-press multi-select — while the list is [data-selecting], reveal the row
   checkbox on touch (normally md-only) and tint selected rows. */
[data-selecting] .mail-row-check {
  display: grid;
}

.mail-swipe__row:has(input[type="checkbox"]:checked) {
  background: var(--color-accent-soft);
}

/* ── Pull-to-refresh (mobile--pull-refresh wraps the list) ──────────────────
   The wrapper clips; the hint slides down into view from above the list as the
   controller writes --pull-distance during the drag, and is clipped away again
   when released. Transform tracks the finger 1:1 (direct, no lag). */
.mail-pull {
  overflow: hidden;
}

.mail-pull-hint {
  position: absolute;
  inset-inline: 0;
  top: 0;
  z-index: 2;
  display: flex;
  justify-content: center;
  padding-block-start: 0.5rem;
  color: var(--color-accent);
  pointer-events: none;
  transform: translateY(calc(var(--pull-distance, 0px) - 2.5rem));
}
