/* ---------- grid ---------- */
.grid {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.col-header {
  flex: none;
  display: grid;
  grid-template-columns: var(--gutter) repeat(var(--cols), var(--cell-size)) var(--gutter);
  background: var(--panel);
  border-bottom: 1px solid var(--border);
  color: var(--muted);
  font-size: .72rem;
  scrollbar-gutter: stable;
}

.col-header .colh {
  text-align: center;
  padding: 4px 0;
}

.col-header .gutter {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.grid-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  position: relative;
  scrollbar-gutter: stable;
}

.grid-sizer {
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
}

.grid-rows {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  will-change: transform;
}

.grid-row {
  display: grid;
  grid-template-columns: var(--gutter) repeat(var(--cols), var(--cell-size)) var(--gutter);
  height: var(--cell-size);
  border-bottom: 1px solid color-mix(in srgb, var(--border) 55%, transparent);
}

.gutter {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  font-size: .68rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.gutter .x {
  opacity: .5;
}

.cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  border: none;
  border-left: 1px solid color-mix(in srgb, var(--border) 45%, transparent);
  background: transparent;
  color: var(--text);
  padding: 2px 0;
  overflow: hidden;
  position: relative;
  /* long-press here opens our own context menu (see bindPointer() in
     grid.js/app.js); without this, mobile browsers show their native
     text-selection magnifier/handles over the glyph first instead. */
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

.cell .glyph {
  font-size: clamp(1rem, calc(var(--cell-size) * 0.42), 1.65rem);
  line-height: 1.05;
  font-family: var(--font-glyph);
}

.cell .cp {
  font-size: clamp(.52rem, calc(var(--cell-size) * 0.11), .72rem);
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* attribute-group color coding: a subtle tint plus a full-color bottom edge,
   so the color reads as a cue without hurting glyph legibility */
.cell[data-group] {
  background: color-mix(in srgb, var(--grp-color, transparent) 11%, transparent);
  box-shadow: inset 0 -2px 0 0 color-mix(in srgb, var(--grp-color, transparent) 55%, transparent);
}

.cell[data-group="letter"] {
  --grp-color: var(--grp-letter);
}

.cell[data-group="mark"] {
  --grp-color: var(--grp-mark);
}

.cell[data-group="number"] {
  --grp-color: var(--grp-number);
}

.cell[data-group="punct"] {
  --grp-color: var(--grp-punct);
}

.cell[data-group="symbol"] {
  --grp-color: var(--grp-symbol);
}

.cell[data-group="emoji"] {
  --grp-color: var(--grp-emoji);
}

.cell[data-group="separator"] {
  --grp-color: var(--grp-separator);
}

.cell[data-group="control"] {
  --grp-color: var(--grp-control);
}

.cell[data-group="format"] {
  --grp-color: var(--grp-format);
}

.cell[data-group="surrogate"] {
  --grp-color: var(--grp-surrogate);
}

.cell[data-group="private"] {
  --grp-color: var(--grp-private);
}

.cell[data-group="unassigned"] {
  --grp-color: var(--grp-unassigned);
}

.cell[data-group="e1"] {
  --grp-color: var(--era-e1);
}

.cell[data-group="e2"] {
  --grp-color: var(--era-e2);
}

.cell[data-group="e3"] {
  --grp-color: var(--era-e3);
}

.cell[data-group="e4"] {
  --grp-color: var(--era-e4);
}

.cell[data-group="e5"] {
  --grp-color: var(--era-e5);
}

.cell[data-group="e6"] {
  --grp-color: var(--era-e6);
}

.cell[data-group="e7"] {
  --grp-color: var(--era-e7);
}

.cell[data-group="e8"] {
  --grp-color: var(--era-e8);
}

.cell[data-group="e9"] {
  --grp-color: var(--era-e9);
}

.cell[data-group="e10"] {
  --grp-color: var(--era-e10);
}

.cell[data-group="e11"] {
  --grp-color: var(--era-e11);
}

.cell[data-group="e12"] {
  --grp-color: var(--era-e12);
}

.cell[data-group="e13"] {
  --grp-color: var(--era-e13);
}

.cell[data-group="e14"] {
  --grp-color: var(--era-e14);
}

.cell[data-group="e15"] {
  --grp-color: var(--era-e15);
}

.cell[data-group="e16"] {
  --grp-color: var(--era-e16);
}

.cell[data-group="e17"] {
  --grp-color: var(--era-e17);
}

.cell:hover {
  background: color-mix(in srgb, var(--accent) 16%, transparent);
}

/* Restricted to real pointer/hover devices (mouse), not touch: the main
   符号表 grid virtualizes its rows (rebuilding cells on every scroll frame
   -- see grid.js render()), and touch browsers track :active by *screen
   position*, not element identity. Scrolling shifts new cells under a touch
   point that's still considered "down", so whatever cell ends up there
   inherits a stuck-looking highlight that was really meant for the one
   originally tapped. grid.js manages its own .pressed class explicitly
   instead (cleared on pointerup/cancel/leave/scroll), which doesn't have
   this failure mode. */
@media (hover: hover) and (pointer: fine) {
  .cell:active {
    background: color-mix(in srgb, var(--accent) 28%, transparent);
  }
}

.cell.pressed {
  background: color-mix(in srgb, var(--accent) 28%, transparent);
}

.cell.fav {
  box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--list-badge-color, var(--fav)) 65%, transparent);
}

.cell.fav[data-group] {
  box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--list-badge-color, var(--fav)) 65%, transparent),
    inset 0 -2px 0 0 color-mix(in srgb, var(--grp-color, transparent) 55%, transparent);
}

.cell.fav::after {
  content: attr(data-badge);
  position: absolute;
  top: 2px;
  right: 3px;
  font-size: .5rem;
  color: var(--list-badge-color, var(--fav));
}

.cell.blank .glyph::before {
  content: "␣";
  color: var(--muted);
  opacity: .5;
}

.cell.blank .glyph {
  color: transparent;
}

.cell.control .glyph {
  font-family: ui-monospace, "SF Mono", Consolas, monospace;
  font-size: clamp(.55rem, calc(var(--cell-size) * 0.22), .85rem);
  font-weight: 600;
  color: var(--muted);
  letter-spacing: -.02em;
}

.cell.empty {
  background: repeating-linear-gradient(45deg, transparent, transparent 5px,
      color-mix(in srgb, var(--border) 30%, transparent) 5px, color-mix(in srgb, var(--border) 30%, transparent) 6px);
  border-left: 1px solid color-mix(in srgb, var(--border) 30%, transparent);
}

/* empty cells (unassigned / surrogate) get a group-tinted hatch instead of
   the neutral one, so those "area attributes" stay visible too */
.cell.empty[data-group] {
  background: repeating-linear-gradient(45deg, transparent, transparent 5px,
      color-mix(in srgb, var(--grp-color, var(--border)) 32%, transparent) 5px,
      color-mix(in srgb, var(--grp-color, var(--border)) 32%, transparent) 6px);
}

.cell.flash {
  animation: cell-flash 1.3s ease;
  z-index: 1;
}

@keyframes cell-flash {

  0%,
  100% {
    box-shadow: inset 0 0 0 0 transparent;
    background: transparent;
  }

  15% {
    box-shadow: inset 0 0 0 2px var(--accent);
    background: color-mix(in srgb, var(--accent) 34%, transparent);
  }

  60% {
    box-shadow: inset 0 0 0 2px var(--accent);
    background: color-mix(in srgb, var(--accent) 22%, transparent);
  }
}

