/**
 * style.css —— 轻量聊天室的全部样式。
 *
 * 本文件职责：
 *     负责页面的全部外观：整体布局、消息气泡、连接状态颜色、移动端适配。
 *     只做样式，不参与任何逻辑（改样式不需要动 JS，改逻辑也不需要动这里）。
 *
 * 被谁使用：
 *     index.html 通过 <link rel="stylesheet" href="./css/style.css"> 引入。
 *
 * 建议的阅读顺序：
 *     1. 变量区（:root）——所有颜色集中在这里，想换配色只改这一处
 *     2. 全局与布局   ——body 撑满一屏、纵向排布，消息列表占据中间的可伸缩空间
 *     3. 各区域样式   ——顶部栏、登录区、状态提示、消息列表、发送区
 *     4. 响应式       ——小屏幕（手机）下的调整
 */

/* ===========================================================================
   1. 变量区
   ===========================================================================
   把颜色、圆角这些会重复用到的值定义成 CSS 变量（自定义属性）。
   好处：想统一调整配色时只改这里，不用在几百行样式里搜索替换颜色值。
   用法：下面用 var(--主色) 这样的写法引用。 */
:root {
  /* 页面主色，用于标题、按钮、自己发的消息气泡 */
  --color-primary: #3b82f6;

  /* 页面背景与卡片背景 */
  --color-bg: #f3f4f6;
  --color-surface: #ffffff;

  /* 文字颜色：正文、次要信息（昵称、时间） */
  --color-text: #1f2937;
  --color-text-muted: #6b7280;

  /* 边框与分割线 */
  --color-border: #e5e7eb;

  /* 状态颜色：正在连接（橙）、已连接（绿）、已断开（红）、错误提示（红） */
  --color-warning: #d97706;
  --color-success: #16a34a;
  --color-danger: #dc2626;

  /* 别人发的消息气泡底色 */
  --color-bubble-other: #ffffff;

  /* 统一的圆角大小 */
  --radius: 12px;
}

/* ===========================================================================
   2. 全局与整体布局
   =========================================================================== */

/* box-sizing: border-box 让元素的 width 包含 padding 和 border。
   不设置的话，给输入框加 padding 会把宽度撑出容器，导致布局错位。
   这是最值得养成习惯的一条全局样式。 */
*,
*::before,
*::after {
  box-sizing: border-box;
}

/*
  [hidden] 强制不显示。
  为什么需要它：浏览器默认样式表里虽然也有 [hidden] { display: none }，
  但作者样式表的优先级**总高于**浏览器默认样式表。
  下面我们给 .message-list 和 .send-area 写了 display: flex，
  它们会盖掉默认的 [hidden]，导致 hidden 属性失效、元素照样显示出来。
  所以必须自己再声明一次，并且加 !important 确保一定生效。
*/
[hidden] {
  display: none !important;
}

body {
  /* 去掉浏览器给 body 的默认外边距（默认 8px，会露出白边） */
  margin: 0;

  /* 字体：优先用系统自带字体，不需要加载任何网络字体，中文显示也最好看 */
  font-family: system-ui, -apple-system, 'Segoe UI', 'Microsoft YaHei', sans-serif;
  font-size: 16px;
  line-height: 1.5;
  color: var(--color-text);
  background: var(--color-bg);

  /*
    整体布局：用 flex 纵向排列各区块。
    100dvh 是"动态视口高度"，在手机浏览器上会随着地址栏收起/展开自动调整；
    用旧的 100vh 在手机上会把输入框顶到屏幕外。dvh 不支持时自动退回 100vh（上一行）。
  */
  height: 100vh;
  height: 100dvh;

  /* 让页面内容居中，并限制最大宽度（宽屏下聊天框不至于拉得特别长，不好读） */
  max-width: 760px;
  margin: 0 auto;

  /* 上右下左的内边距，四周留白 */
  padding: 16px;

  /* 让 flex 子元素在纵向排布 */
  display: flex;
  flex-direction: column;

  /* 各区块之间的间距 */
  gap: 12px;
}

/* ===========================================================================
   3. 顶部栏与标题
   =========================================================================== */

/* 顶部栏：左边是标题，右边是「退出登录」按钮。
   justify-content: space-between 的作用是"把仅有的两个子元素分别推到两端"——
   比给标题写 margin-right: auto 更直白，以后再加第三个元素（比如在线人数），
   它会自动排在正中间，不用改这里的写法。 */
.app-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

h1 {
  /* 标题不需要很大，这里只作为页面标识，把空间留给消息列表 */
  margin: 0;
  font-size: 20px;
  /* 注意这里**没有** text-align: center：
     标题和退出按钮并排之后，居中会让标题的位置随着按钮宽度变化忽左忽右，
     现在由 .app-header 的 space-between 决定位置，标题自然靠左。 */
  /* 稍微收紧字距，视觉上更紧凑 */
  letter-spacing: 1px;
}

/* 退出登录按钮：次要按钮。
   类选择器（.logout-button）的优先级高于上面通用的元素选择器（button），
   所以能稳定盖掉那些蓝底白字的样式，不需要写 !important。
   为什么不用主色蓝：它的使用频率远低于「发送」，
   视觉上放轻一点，既不会抢注意力，也能降低误点的概率。 */
.logout-button {
  padding: 6px 12px;
  font-size: 13px;
  color: var(--color-text-muted);
  background: var(--color-bg);
  /* 灰底 + 一圈细边框，在白底页面上才有清楚的边界 */
  border: 1px solid var(--color-border);
}

/* 悬停时轻微加深，给出「可以点」的反馈。
   这里显式写 filter: none 覆盖上面那条通用的 button 悬停规则——
   那条用 brightness() 调亮度是给蓝底按钮准备的，套到灰底按钮上会发暗发脏。 */
.logout-button:hover:not(:disabled) {
  color: var(--color-text);
  background: var(--color-border);
  filter: none;
}

/* ===========================================================================
   4. 登录 / 注册区
   =========================================================================== */

/*
  登录区整体：纵向排列两行输入 + 一行按钮，行与行之间留 10px。
  以前是「一行搞定」的横排（只有一个昵称输入框），
  现在要放下用户名和密码两个字段，横着排会把输入框挤得只剩一点点宽，
  所以改成纵向三行，手机上也不用再单独妥协。
*/
.auth-area {
  display: flex;
  flex-direction: column;
  gap: 10px;

  /* 卡片样式：白底、圆角、内边距、细边框 */
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 12px;
}

/* 一行 = 一个标签 + 一个输入框，横向排并垂直居中 */
.auth-row {
  display: flex;
  align-items: center;
  gap: 8px;
}

.auth-row label {
  color: var(--color-text-muted);
  /* 标签不参与伸缩，保持文字宽度；输入框则占据剩余空间 */
  flex: 0 0 auto;
  /*
    固定标签宽度，让「用户名」「密码」两个标签左边缘对齐，输入框也就能对齐。
    3em 是"3 个字符宽"，正好放得下"用户名"三个汉字；
    写固定值而不是靠内容撑开，是因为两个字和三个字的标签宽度不同，
    不对齐的话两行输入框会错开，看起来像没做完。
  */
  width: 3em;
}

/* 按钮行：靠右排列，「登录」在左、「注册」在右 */
.auth-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

/*
  次要按钮（灰底）：目前「注册」和「退出登录」用它，区别于蓝底的主操作。
  这里用类选择器而不是 #id，是为了以后再加次要按钮时可以直接复用。
  （.logout-button 有自己的历史写法，行为一致，就不去动它了，
    避免改了它反而引入回归。）
*/
.secondary-button {
  color: var(--color-text);
  background: var(--color-border);
}

/* 悬停时轻微加深。显式写 filter: none 覆盖上面 button 那条通用规则——
   那条用 brightness() 调亮度是给蓝底按钮准备的，套到灰底按钮上会发暗发脏。 */
.secondary-button:hover:not(:disabled) {
  color: var(--color-text);
  background: #d7dbe0;
  filter: none;
}

/* ===========================================================================
   5. 输入框与按钮的公共样式
   =========================================================================== */

/* 输入框：占据父容器的剩余空间（flex: 1），这样它能自然地把按钮挤到最右边。
   注意这里同时选中 text 和 password 两种类型：
   密码框的 type 是 password，如果只写 text，密码框就一点样式都没有，
   在页面里会显得又高又土，和旁边的用户名框完全不像一套。 */
input[type='text'],
input[type='password'] {
  flex: 1;
  /* min-width: 0 是 flex 布局里的经典坑：
     flex 子元素的默认最小宽度是内容宽度，输入框内容很长时会把容器撑破。
     设为 0 才能让它真正"可以被压缩"。 */
  min-width: 0;
  padding: 8px 10px;
  font-size: 15px;
  font-family: inherit;
  color: inherit;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 8px;
  /* 输入框聚焦时用 outline 做提示，这里先把默认描边去掉，下面 :focus 里再自定义 */
  outline: none;
}

/* :focus-visible 只在"键盘操作聚焦"时生效（鼠标点击不触发），
   这样既保证了键盘用户能看清焦点在哪，又不会让鼠标点击时出现难看的外框 */
input[type='text']:focus-visible,
input[type='password']:focus-visible {
  border-color: var(--color-primary);
  /* 用外阴影做一圈淡淡的高亮，比 outline 更柔和 */
  box-shadow: 0 0 0 3px rgb(59 130 246 / 15%);
}

/* 输入框被禁用时（HTTP 降级发送的那一小段时间）视觉上变灰，提示用户暂时不能输入 */
input[type='text']:disabled,
input[type='password']:disabled {
  background: var(--color-bg);
  cursor: not-allowed;
}

button {
  /* flex: 0 0 auto 表示"不放大也不缩小"，按钮宽度完全由文字决定 */
  flex: 0 0 auto;
  padding: 8px 16px;
  font-size: 15px;
  font-family: inherit;
  color: #fff;
  background: var(--color-primary);
  border: none;
  border-radius: 8px;
  cursor: pointer;
}

/* 鼠标悬停时压暗一点。用 filter 调亮度，不用再定义一个新颜色 */
button:hover:not(:disabled) {
  filter: brightness(0.94);
}

/* 禁用状态：变灰 + 禁止点击光标 */
button:disabled {
  background: var(--color-text-muted);
  cursor: not-allowed;
}

/* ===========================================================================
   6. 连接状态提示
   =========================================================================== */

.connection-status {
  margin: 0;
  font-size: 13px;
  text-align: center;
  color: var(--color-text-muted);
}

/* 未加入聊天室：灰色。页面刚打开时、以及点了「退出登录」之后都是这个状态。
   它和其他三种状态是并列的，所以这里显式写一条规则而不是依赖上面的默认颜色，
   目的是让"四种状态"在样式表里一眼看全，以后改配色时不会漏掉这一种。 */
.connection-status.is-idle {
  color: var(--color-text-muted);
}

/* 正在连接：橙色。用动画让文字缓慢呼吸，提示"还在努力中" */
.connection-status.is-connecting {
  color: var(--color-warning);
  animation: status-pulse 1.6s ease-in-out infinite;
}

/* 已连接：绿色 */
.connection-status.is-open {
  color: var(--color-success);
}

/* 已断开：红色 */
.connection-status.is-closed {
  color: var(--color-danger);
}

/* 呼吸动画：透明度在 1 和 0.45 之间来回变化 */
@keyframes status-pulse {
  0%,
  100% {
    opacity: 1;
  }

  50% {
    opacity: 0.45;
  }
}

/* ===========================================================================
   7. 提示信息区（错误提示）
   =========================================================================== */

.hint {
  margin: 0;
  font-size: 13px;
  text-align: center;
  color: var(--color-text-muted);
}

/* 没有内容时整个元素不占位置，避免页面上多出一段空白 */
.hint:empty {
  display: none;
}

/* 错误类型的提示用红色 */
.hint.is-error {
  color: var(--color-danger);
}

/* 普通信息（不是错误）用灰色，例如「注册成功，正在登录…」「已退出登录」。
   它和 .hint 的默认颜色一样，这里显式写一遍是为了让"两种提示类型"在样式表里
   一眼看全（和上面 .connection-status.is-idle 是同样的考虑）：
   以后想给普通提示换个颜色（比如改成绿色），知道该改哪一条。 */
.hint.is-info {
  color: var(--color-text-muted);
}

/* ===========================================================================
   8. 消息列表（页面主体，占据中间所有可伸缩空间）
   =========================================================================== */

.message-list {
  /*
    这是整个布局的关键：flex: 1 让消息列表吃掉 body 里除其他区块外的全部剩余高度。
    这样无论窗口多高，输入框都被压在底部，只有消息列表滚动。
    写法说明：flex: 1 是 flex-grow:1 / flex-shrink:1 / flex-basis:0% 的简写。
    （严格说简写时 flex-basis 应当写 0%，这里写 0 在浏览器里会被当成 0px，效果一致。）

    min-height: 0 同样是 flex 布局的经典坑，和输入框的 min-width: 0 同理：
    flex 子元素默认最小高度是内容高度，消息一多，列表就会被内容撑高、
    把输入框挤出屏幕，滚动条也不会出现。必须设为 0 才能正常滚动。
  */
  flex: 1;
  min-height: 0;
  overflow-y: auto;

  margin: 0;
  padding: 12px;

  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);

  /* 用 flex 纵向排列消息，gap 控制每条消息之间的间距 */
  display: flex;
  flex-direction: column;
  gap: 10px;

  /* 去掉 <ul> 默认的圆点符号 */
  list-style: none;

  /* 让列表内的滚动更顺滑（触屏和触控板体验） */
  -webkit-overflow-scrolling: touch;
}

/* ===========================================================================
   9. 单条消息
   =========================================================================== */

.message-item {
  /* 气泡最大只占 80% 宽度，留出留白，让人一眼能看出"左一句右一句"的对话感 */
  max-width: 80%;

  padding: 8px 12px;
  background: var(--color-bubble-other);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);

  /* 默认靠左（别人发的消息） */
  align-self: flex-start;
}

/* 自己发的消息：靠右显示 + 用主色底 + 白字，和别人的消息区分开。
   这个类由 ui.js 在渲染时根据昵称是否等于自己来添加。 */
.message-item--self {
  align-self: flex-end;
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: #fff;
}

/* 消息的第一行：昵称 + 时间 */
.message-meta {
  display: flex;
  /* 昵称和时间紧挨着排，用 gap 分隔 */
  align-items: baseline;
  gap: 8px;
  font-size: 12px;
  color: var(--color-text-muted);
}

/* 自己发的消息里，昵称和时间也跟着变成半透明白色，否则灰色在蓝底上几乎看不清 */
.message-item--self .message-meta {
  color: rgb(255 255 255 / 80%);
  /* 自己发了什么比"自己叫啥"更值得看，所以把昵称和时间推到右边，靠后的位置 */
  justify-content: flex-end;
}

.message-nickname {
  font-weight: 600;
}

.message-time {
  /* 时间用等宽字体，数字宽度一致，多条消息竖着排时看起来更整齐 */
  font-variant-numeric: tabular-nums;
}

/* 消息正文 */
.message-content {
  margin: 2px 0 0;
  font-size: 15px;

  /*
    长单词 / 长链接不断行会把气泡撑爆（横向溢出容器）。
    overflow-wrap: break-word 允许在"实在放不下时"从单词中间断开换行，
    这是处理用户输入最省事也最不容易出问题的方式。
  */
  overflow-wrap: break-word;
  /* 兜底：老版本浏览器只认 word-break */
  word-break: break-word;
}

/* ===========================================================================
   10. 输入框与发送按钮区
   =========================================================================== */

.send-area {
  display: flex;
  align-items: center;
  gap: 8px;

  /* 和昵称区保持同样的卡片样式，视觉上前后一致 */
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 12px;
}

/* ===========================================================================
   11. 滚动条美化（可选，只影响 Chrome / Edge / Safari）
   =========================================================================== */

/* 默认滚动条较宽，在窄窄的消息区里显得笨重。这里让它细一点。
   注意：这是非标准属性，Firefox 不支持，不支持时会自然退回默认样式，不影响功能。 */
.message-list::-webkit-scrollbar {
  width: 8px;
}

.message-list::-webkit-scrollbar-thumb {
  background: var(--color-border);
  border-radius: 4px;
}

/* 鼠标悬停在滚动条上时颜色加深，方便抓住它 */
.message-list::-webkit-scrollbar-thumb:hover {
  background: var(--color-text-muted);
}

/* ===========================================================================
   12. 响应式：窄屏（手机）适配
   =========================================================================== */

@media (max-width: 480px) {
  body {
    /* 手机上屏幕本来就小，缩小留白，把空间让给消息 */
    padding: 10px;
    gap: 8px;
  }

  h1 {
    font-size: 17px;
  }

  /* 窄屏上把退出按钮也缩小一档，避免它和标题抢位置（标题字数虽少，
     但加上内边距后，两者在 320px 宽的屏幕上就已经贴着排了） */
  .logout-button {
    padding: 5px 10px;
    font-size: 12px;
  }

  /* 发送区改成上下两行：手机上横排会把输入框挤得只剩一点点宽。
     （登录区本来就是纵向排列的，见 .auth-area，这里不用再处理它。） */
  .send-area {
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
  }

  /*
    改成纵向排列后，输入框不能再沿用上面的 flex: 1。
    flex: 1 等价于 flex-basis: 0%，它是为"横向撑满剩余宽度"设计的；
    在纵向布局里变成了"高度撑满"，某些浏览器会把输入框高度算成接近 0，
    输入框就"消失"了。这里改回按自身内容高度显示，最稳妥。
  */
  .send-area input[type='text'] {
    flex: 0 0 auto;
  }

  /* 改成纵向排列后按钮会占满整行，这里让它不要太宽 */
  .send-area button {
    align-self: flex-end;
    padding: 8px 14px;
  }

  /* 登录区一行里的输入框同样要防止被压扁（标签占了固定宽度，屏幕更窄） */
  .auth-row input[type='text'],
  .auth-row input[type='password'] {
    flex: 1 1 auto;
  }

  /* 手机上标签宽度按内容算，把省下来的宽度让给输入框 */
  .auth-row label {
    width: auto;
  }

  /* 手机上气泡可以更宽一些，否则一屏放不下几个字 */
  .message-item {
    max-width: 88%;
  }
}

/* 尊重用户的"减少动态效果"系统设置：
   有些用户会因为前庭功能问题对动画不适，系统里可以关掉动画。
   这里对应地把连接状态那个呼吸动画取消掉。 */
@media (prefers-reduced-motion: reduce) {
  .connection-status.is-connecting {
    animation: none;
  }
}
