/* chat/01_tokens_reset.css
 * ------------------------------------------------------------
 * Split 1 of 10 from web/account/css/chat.css (CLAUDE.md §8.16 — the
 * 850-line hard limit now applies to hand-edited CSS, not only Dart; the
 * split is purely mechanical, see chat.html for the load order and this
 * file's own place as FIRST in it).
 *
 * Covers: the file-level design notes for the whole chat surface (why it
 * is a fixed-width phone layout, which region scrolls and why it is not
 * always the same one, why translucent washes use color-mix() instead of
 * new tokens), the page-wide CSS reset (box-sizing, button/input/textarea
 * chrome stripped), the screen-reader-only aria-live region, the
 * surface-wide focus-visible ring and its text-field exception, and the
 * prefers-reduced-motion override. Everything here applies before any
 * component-specific rule in the files that follow.
 * ------------------------------------------------------------ */

/* chat.css
 * ------------------------------------------------------------
 * Stylesheet for /account/chat.html — the browser chat client
 * (docs/kravspec_web_chat.md). Loaded alongside /_shared/tokens.css and
 * NOTHING else: not account.css, which is the portal's light theme and
 * defines --card/--border/--green with different values than this page
 * wants. This is the app's dark WhatsApp-style chat theme (CLAUDE.md §6),
 * and every colour below is one of the --chat-* custom properties
 * tokens.css generates from lib/core/constants/app_colors.dart. There is
 * no hex literal anywhere in this file for that reason — a colour tokens.css
 * does not have is a design GAP to raise with the owner, not something to
 * invent locally, because inventing it here is exactly the drift the
 * generation step exists to prevent.
 *
 * THE FORM IS A PHONE, NOT A RESPONSIVE WEBSITE
 *
 * Fixed max-width 400px, centred, full height. There is no breakpoint that
 * widens this layout — see app_shell.js's own header for why a two-pane
 * desktop layout is a different product, not a bigger version of this one.
 *
 * WHICH REGION SCROLLS, AND WHY IT IS NOT ALWAYS THE SAME ONE
 *
 * "The scrolling region must be the only thing that scrolls" (app_shell.js)
 * is a requirement about the DOCUMENT, not about any one component: if the
 * real page <body> scrolls too, the fixed header/footer visibly drift on a
 * mobile browser as its chrome shows and hides, and the composer ends up
 * behind the on-screen keyboard. The fix here is that .chat-shell__body
 * itself never scrolls (overflow:hidden, a flex child sized to fill the
 * space between header and footer) — the SCREEN currently mounted inside
 * it owns the one scrolling region, and which element that is differs by
 * screen on purpose: the thread view builds its own internal scroll
 * container (./ui/thread_scroll.js — infinite-scroll anchoring lives
 * there), while the list view has no such container in its own DOM, so
 * .chat-list-view__content is given the scroll here in CSS instead. Either
 * way there is exactly one scrolling element on screen at a time, and the
 * true <body> — set to overflow:hidden below — never joins in.
 *
 * COLOUR-MIX, NOT NEW TOKENS, FOR TRANSLUCENT WASHES
 *
 * A handful of surfaces need something tokens.css has no dedicated name
 * for — a hover wash on a list row, the scrim behind the lightbox, a
 * skeleton's shimmer block. Rather than inventing a hex for any of them,
 * every one of those is `color-mix(in srgb, var(--chat-...) N%, transparent)`
 * — a translucency DERIVED from an existing generated token, so it moves
 * automatically if that token's colour is ever regenerated from
 * app_colors.dart, and a `grep -E "#[0-9a-fA-F]"` over this file still
 * finds nothing to flag. The handful used more than once are named below
 * as their own custom properties so the intent ("this is a hover wash", not
 * "this is a random 8% mix") stays legible at every call site.
 * ------------------------------------------------------------ */

/* ===== Reset + document-level frame ===== */

/* A page-wide reset is safe here (unlike account.css sharing eight pages'
   worth of unrelated markup) because this stylesheet has exactly one page
   to serve. box-sizing:border-box on everything is what lets every width
   below include its own padding/border without a separate calc(). */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html, body { height: 100%; }

body {
  /* overflow:hidden is the other half of the single-scroll-region rule
     above: the real document body must never be the thing that scrolls,
     or the phone's fixed bars would drift with it on a mobile browser. */
  overflow: hidden;
  background: var(--chat-bg);
  color: var(--chat-bubble-text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
  /* Centres the fixed-width phone column on any viewport wider than
     400px — see the file header: this is the one layout, not a narrowest
     breakpoint of a wider one. */
  display: flex;
  justify-content: center;
}

button {
  /* A shared reset for every custom button the ui/ layer builds (list
     rows, the composer's controls, the lightbox chrome, …) so each
     component only has to declare what makes IT different, not restate
     "no default button chrome" thirty times. Specific components override
     background/color/cursor below where they need to look like something
     other than plain text. */
  font: inherit;
  color: inherit;
  background: none;
  border: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* Text fields are stripped of the browser's own chrome, exactly as `button`
   is just above — that omission was a visible bug, not a harmless gap.
   Every field in this surface draws itself with a filled background and a
   20px radius (the composer's textarea, the list's search box), so the
   control's DEFAULT border sat OUTSIDE that radius as a second, squarer
   outline. Focus a field and there were three rings at once: the default
   border, the rounded fill, and the surface's own :focus-visible ring below.
   Reported on both fields independently before the cause was found — which is
   the tell that it belonged here in the reset rather than on each field.

   `appearance: none` is what removes it on WebKit, where a border alone is not
   enough: `input[type=search]` carries native search-field styling (its own
   inset shape and inner decorations) that ignores the border property. The
   file input in ui/image_attach.js is unaffected by any of this — it is never
   appended to the document, so no CSS reaches it.

   The focus ring is deliberately NOT removed here: this client is meant to be
   keyboard-driven, and .chat-shell :focus-visible below is its replacement —
   one clear ring instead of three competing ones. */
input, textarea {
  font: inherit;
  color: inherit;
  border: none;
  appearance: none;
  -webkit-appearance: none;
}
a { color: inherit; text-decoration: none; }
img, video { display: block; max-width: 100%; }

/* Visible, not merely present: a screen-reader-only pattern for the shell's
   aria-live region (app_shell.js's `announce`) — it must exist in the
   accessibility tree and never on screen, which display:none would also
   achieve but would additionally stop some assistive tech from announcing
   changes inside it. */
.chat-shell__announce {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* A visible, clearly-styled focus ring everywhere in the surface — this
   client is explicitly meant to be pc-keyboard-driven (kravspec §12.5
   point 6), so removing the outline without a replacement is not an option.

   The colour is the BRAND accent, --primary (the sage green of CLAUDE.md §6),
   not --chat-read-tick. Both are real palette entries, but read-tick means one
   specific thing: app_colors.dart:108 calls it the "WhatsApp-blue 'read'
   double-check", and it is what tells a sender their message was read. Using a
   status colour as an interaction colour makes the two say the same thing in
   different places — and in a chat, where blue ticks carry meaning, that is
   actively confusing rather than merely untidy.

   Contrast is fine for the swap: sage on this surface's near-black background
   clears the 3:1 an indicator needs, so this is a correction of MEANING and not
   a trade of legibility for prettiness. */
.chat-shell :focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* …with one exception: the text fields.
   A detached, offset ring is right for a BUTTON — it traces a shape the eye
   already reads as a control. On a filled, pill-shaped text field it reads as
   a second border floating around the box, which is what it was mistaken for.
   Worse, it shows up on an ordinary mouse click: per spec a text field matches
   :focus-visible however it was focused, because it is about to receive
   keystrokes. So the loudest indicator in the surface was firing in its most
   common interaction.

   The indicator is NOT removed — this client is keyboard-driven (kravspec
   §12.5 point 6) and an invisible focus position is exactly what that rule
   forbids. It is restated in the field's own vocabulary: a ring drawn ON the
   edge rather than around it, so the field simply gains an outline it did not
   have, at the same 20px radius as its fill. Same colour, same 2px, same
   contrast against the background — only the geometry changes. */
.chat-shell .chat-composer__input:focus-visible,
.chat-shell .chat-list-view__search:focus-visible {
  outline-offset: -2px;
}

/* Standard reduced-motion override (the well-known pattern, not a novel
   one): forcing every animation/transition to near-zero duration is the
   only reliable way to guarantee NOTHING in the surface still animates
   once a reader has asked for less motion, regardless of which
   component's own selector would otherwise win the cascade — which is
   also why this is the one place in the file `!important` is used. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

