/* ============================================================
   INK WASH TABS (墨流し)
   Unified header + nav panel for grid mode
   Merges hero-top-bar + ink-wash-nav into one floating surface
   ============================================================ */

/* ============================================================
   DESIGN TOKENS (supplement base.css tokens)
   ============================================================ */
:root {
  --status-known: #7B8B6F;
  --status-learning: var(--color-amber);
  --status-new: #5B7B8C;
  --text-tertiary: var(--color-faint);
  --radius-panel: 12px;
  --radius-pill: 999px;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ink-ease: cubic-bezier(0.25, 0.46, 0.45, 0.94);
  --transition-smooth: 280ms var(--ease-out);
  --transition-ink: 480ms var(--ink-ease);
  --transition-slow: 480ms var(--ease-out);
}

/* ============================================================
   NAV BAR CONTAINER
   Fixed at top, visible only in grid mode
   ============================================================ */
.ink-wash-nav {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  padding: 0 24px;
  pointer-events: none;
  transition: transform 250ms var(--ease-out),
              left 250ms cubic-bezier(0.16, 1, 0.3, 1),
              right 250ms cubic-bezier(0.16, 1, 0.3, 1);
}

/* Push entire nav right when browse sidebar is open (sidebar flush at left:0) */
body.browse-sidebar-open .ink-wash-nav {
  left: var(--sidebar-w, 260px);
  padding: 0 calc(40px + var(--grid-scrollbar-w, 0px)) 0 40px;
}

/* Fill nav width edge-to-edge — outer padding handles alignment */
body.browse-sidebar-open .nav-bar-inner,
body.settings-sidebar-open .nav-bar-inner {
  margin-left: 20px;
  margin-right: 20px;
  max-width: none;
}

.ink-wash-nav.nav-hidden {
  transform: translateY(-100%);
}

.nav-hover-zone {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 12px;
  z-index: 101;
  pointer-events: auto;
}
/* desktop polish round 2 (13 October 2026), finding 9: the desktop beam never
   hides, so its reveal strip has nothing to reveal and would only lie over the
   beam's top 12px eating clicks. grid-mode.js no longer makes it on a wide
   window; this covers a strip a narrow window made before it was widened. */
@media (min-width: 769px) {
  .nav-hover-zone { display: none; }
}

body.grid-mode .ink-wash-nav {
  display: block;
}

/* Hide old header + branding in grid mode — unified nav absorbs brand + settings */
body.grid-mode .hero-top-bar,
body.grid-mode .app-branding-topleft {
  display: none;
}

/* Hide when overlays are open */
body:has(.quiz-modal-overlay.active) .ink-wash-nav,
body.focus-mode .ink-wash-nav,
body.video-mode .ink-wash-nav,
body.chat-mode .ink-wash-nav {
  display: none;
}
/* desktop polish round 2 (13 October 2026), finding 8: the lookup palette no
   longer takes the wall's beam away. On desktop the palette is a quiet card
   over a scrim (z 9800/9900) and the beam (z 100) simply rests under it;
   removing the beam made the wall jump by the beam's height on every ⌘K
   (--nav-bar-total-height fell to 0) and the hall's beam never did it. The
   phone's palette is a full-screen sheet, so the phone keeps the rule. */
@media (max-width: 768px) {
  body:has(.vocab-panel.open) .ink-wash-nav {
    display: none;
  }
}

.nav-bar-inner {
  max-width: 1800px;
  margin: 12px auto 0;
  background: var(--card-surface, #FAFAF7);
  border-radius: var(--radius-panel);
  box-shadow: 0 1px 4px rgba(44,44,44,0.025), 0 0 1px rgba(44,44,44,0.03);
  overflow: visible;
  pointer-events: auto;
  position: relative;
  border-bottom: 1px solid rgba(44,44,44,0.02);
  /* Washi grain — quieted (texture budget moved to the card calligraphy face) */
  background-image: url("data:image/svg+xml,%3Csvg width='200' height='200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)' opacity='0.012'/%3E%3C/svg%3E");
}

/* ============================================================
   GLOBAL RESET for ink-wash nav buttons
   Neutralizes leaking styles from components.css and standard-mode.css
   ============================================================ */
.ink-wash-nav button {
  background: transparent;
  box-shadow: none;
  transform: none;
}
/* desktop polish round 2 (13 October 2026), finding 3: the width reset spares
   the lookup glass. `width: auto` here is 0-1-1 and outranked the glass's
   shared seat (.lookup-glass, 0-1-0, css/vocab-palette.css), so the wall's
   glass shrank to its bare svg (18px wide) while the hall's stood in its full
   seat. :where() adds nothing to the specificity, so every other beam button
   meets the same 0-1-1 reset as before. */
.ink-wash-nav button:not(:where(.lookup-glass)) {
  width: auto;
}

.ink-wash-nav button:hover {
  transform: none;
  box-shadow: none;
}

.ink-wash-nav button:active {
  transform: none;
}

/* ============================================================
   YOKOGA BRUSH STROKE — sweeps across header on mode switch
   横画 (horizontal stroke), 2px, semi-transparent, 600ms
   ============================================================ */
.ink-wash-nav .brush-stroke {
  position: absolute;
  top: 50%;
  left: -10%;
  width: 0;
  height: 2px;
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(44, 44, 44, 0.08) 10%,
    rgba(44, 44, 44, 0.14) 40%,
    rgba(44, 44, 44, 0.14) 60%,
    rgba(44, 44, 44, 0.08) 90%,
    transparent 100%
  );
  transform: translateY(-50%);
  border-radius: 1px;
  z-index: 10;
  pointer-events: none;
}

.ink-wash-nav .brush-stroke.animate {
  animation: brushSweep 600ms var(--ink-ease) forwards;
}

@keyframes brushSweep {
  0% { width: 0; left: -10%; opacity: 0; }
  15% { opacity: 1; }
  50% { width: 120%; opacity: 0.8; }
  100% { width: 120%; left: 0%; opacity: 0; }
}

/* ============================================================
   HEADER ROW — brand + search icon + modes + utils
   ============================================================ */
.ink-wash-nav .header-row {
  display: flex;
  align-items: center;
  height: 56px;
  padding: 0 12px 0 18px;
  gap: 14px;
  position: relative;
  z-index: 2;
}

/* Brand */
.ink-wash-nav .nav-brand {
  user-select: none;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  /* The brand mark is a BUTTON now — logo click = home (full unfiltered
     browse). Native chrome stripped; resting look identical to the old
     static brand. */
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  cursor: pointer;
}

/* Quiet hover affordance: the hanko tilts a hair, nothing else moves. */
.ink-wash-nav .nav-brand .brand-logo {
  transition: transform 0.2s var(--ease-settle, ease-out);
}

.ink-wash-nav .nav-brand:hover .brand-logo {
  transform: rotate(-4deg);
}

.ink-wash-nav .nav-brand:focus-visible {
  outline: 2px solid var(--color-accent, #3D5A80);
  outline-offset: 3px;
  border-radius: 6px;
}

.ink-wash-nav .brand-logo {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  object-fit: cover;
}

/* .brand-text typography comes from the canonical .kotoba-wordmark--nav
   (css/brand.css §8) carried in the markup — no local copy to drift. */

/* Spacer */
.ink-wash-nav .header-spacer { flex: 1; }



/* ============================================================
   MODE SELECTOR — segmented control with sliding indicator
   ============================================================ */
.ink-wash-nav .mode-selector {
  display: flex;
  align-items: center;
  gap: 2px;
  background: transparent;
  border-radius: var(--radius-pill);
  padding: 0;
  position: relative;
  flex-shrink: 0;
}

/* Sliding indicator — moves behind the active button */
.ink-wash-nav .mode-indicator {
  position: absolute;
  top: 0;
  left: 0;
  height: 34px;
  background: rgba(44,44,44,0.035);
  border-radius: 10px;
  box-shadow: none;
  transition: all 380ms cubic-bezier(0.4, 0, 0.2, 1);
  z-index: 0;
  pointer-events: none;
}

/* Ink bleed — sumi ink bleeding at edges during transition */
.ink-wash-nav .mode-indicator::before {
  content: '';
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  background: radial-gradient(
    ellipse 120% 100% at 50% 100%,
    rgba(44, 44, 44, 0.04) 0%,
    transparent 70%
  );
  opacity: 0;
  transition: opacity 500ms ease;
}

.ink-wash-nav .mode-selector.transitioning .mode-indicator::before {
  opacity: 1;
}

.ink-wash-nav .mode-btn {
  position: relative;
  z-index: 1;
  height: 34px;
  padding: 0 16px;
  border: none;
  border-radius: 10px;
  background: transparent;
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--text-secondary, #57534e);
  cursor: pointer;
  transition: color 350ms var(--ink-ease);
  white-space: nowrap;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0;
}

.ink-wash-nav .mode-btn .mode-label {
  line-height: 1;
}

.ink-wash-nav .mode-btn.active {
  color: var(--text-primary, #2C2C2C);
}

.ink-wash-nav .mode-btn:hover:not(.active) {
  color: var(--text-primary, #2C2C2C);
}

/* Keyboard shortcut hint */
.ink-wash-nav .mode-key {
  font-size: 9px;
  font-weight: 400;
  color: var(--text-tertiary, #8C8578);
  opacity: 0;
  transition: opacity var(--transition-smooth);
  margin-left: 2px;
  position: absolute;
  right: 4px;
  top: 3px;
}

.ink-wash-nav .mode-btn:hover .mode-key {
  opacity: 1;
}

/* Play sub-mode dot */
.ink-wash-nav .mode-btn .sub-indicator {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--accent, #3D5A80);
  opacity: 0;
  position: absolute;
  right: 6px;
  bottom: 4px;
  transition: opacity var(--transition-smooth);
}

.ink-wash-nav .mode-btn.has-sub .sub-indicator {
  display: none;
}

/* Play sub-mode popover — anchored to .mode-btn[data-view="video"] (already position:relative) */
.play-mode-popover {
  position: fixed;
  background: var(--card-surface, #FAFAF7);
  background-image: url("data:image/svg+xml,%3Csvg width='200' height='200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)' opacity='0.02'/%3E%3C/svg%3E");
  border: none;
  border-radius: 10px;
  box-shadow: 0 2px 12px rgba(44,44,44,0.06), 0 0 0 1px rgba(44,44,44,0.04);
  padding: 5px;
  z-index: 9999;
  transform: translateX(-50%) translateY(6px);
  opacity: 0;
  transition: opacity 180ms ease, transform 180ms cubic-bezier(0.16, 1, 0.3, 1);
  min-width: 160px;
}
.play-mode-popover.popover-visible {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* Suspended session progress bar inside Play button */
.ink-wash-nav .play-progress-bar {
  position: absolute;
  bottom: 0;
  left: 4px;
  right: 4px;
  height: 2px;
  border-radius: 1px;
  background: rgba(44,44,44,0.06);
  pointer-events: none;
  opacity: 0;
  transition: opacity 300ms ease;
}
.ink-wash-nav .play-progress-bar.visible {
  opacity: 1;
}
.ink-wash-nav .play-progress-fill {
  height: 100%;
  border-radius: 1px;
  background: var(--kintsugi-gold, #C9A96E);
  transition: width 300ms ease;
}
.ink-wash-nav .play-progress-fill.paused {
  animation: pause-breath 3s ease-in-out infinite;
}

/* Paused session — label transitions smoothly between Play/Resume */
.ink-wash-nav .mode-btn .mode-label {
  transition: opacity 150ms ease;
}
@keyframes pause-breath {
  0%, 100% { opacity: 0.65; }
  50% { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .ink-wash-nav .play-progress-fill.paused { animation: none; opacity: 0.85; }
}

.play-mode-popover .popover-item {
  display: block;
  width: 100%;
  padding: 7px 12px;
  margin: 0;
  border: none;
  border-radius: 7px;
  background: none;
  font-family: inherit;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-secondary, #57534e);
  cursor: pointer;
  text-align: left;
  white-space: nowrap;
  -webkit-appearance: none;
  appearance: none;
  -webkit-tap-highlight-color: transparent;
  border-left: 3px solid transparent;
  transition: background 140ms ease, color 140ms ease;
}

.play-mode-popover .popover-item:hover {
  color: var(--accent, #3D5A80);
  background: rgba(61, 90, 128, 0.06);
}
.play-mode-popover .popover-item:focus,
.play-mode-popover .popover-item:focus-visible {
  outline: none;
  box-shadow: none;
}

/* Current selection — gold accent (scarcity: only gold in the toolbar) */
.play-mode-popover .popover-item.current {
  border-left-color: var(--kintsugi-gold, #C9A96E);
  color: #A6883A;
  background: rgba(201, 169, 110, 0.08);
  font-weight: 600;
}
.play-mode-popover .popover-item.current:hover {
  background: rgba(201, 169, 110, 0.13);
}

/* Divider between Learn and Revise */
.play-mode-popover .popover-divider {
  height: 1px;
  background: rgba(44,44,44,0.05);
  margin: 3px 8px;
}

/* Revise parent — chevron hint */
.play-mode-popover .popover-parent::after {
  content: '\203A';
  float: right;
  margin-left: 8px;
  color: var(--text-tertiary, #8C8578);
  transition: transform 250ms cubic-bezier(0.16, 1, 0.3, 1), color 140ms ease;
}
.play-mode-popover .popover-parent:hover::after {
  color: var(--accent, #3D5A80);
}
.play-mode-popover .popover-parent.expanded::after {
  transform: rotate(90deg);
}

/* Collapsible sub-menu */
.play-mode-popover .popover-sub {
  max-height: 0;
  overflow: hidden;
  transition: max-height 250ms cubic-bezier(0.16, 1, 0.3, 1), opacity 200ms ease;
  opacity: 0;
  border: none;
  margin: 0;
  padding: 0;
}
.play-mode-popover .popover-sub.expanded {
  max-height: 80px;
  opacity: 1;
}
.play-mode-popover .popover-sub-item {
  padding-left: 24px;
  font-size: 11.5px;
  font-weight: 400;
}
.play-mode-popover .popover-sub-item.current {
  font-weight: 500;
}

/* Gold flash on selection */
@keyframes popover-gold-flash {
  0%   { background: rgba(201, 169, 110, 0.25); }
  100% { background: rgba(201, 169, 110, 0.08); }
}
.play-mode-popover .popover-item.flash {
  animation: popover-gold-flash 150ms ease-out;
}

.play-mode-popover .popover-session-info {
  padding: 6px 16px 2px;
  font-size: 11px;
  color: var(--text-tertiary, #8C8578);
  white-space: nowrap;
  letter-spacing: 0.01em;
}

.play-mode-popover .popover-end-session {
  font-size: 11.5px;
  color: var(--text-tertiary, #8C8578);
  border-top: 1px solid rgba(44,44,44,0.04);
  margin-top: 2px;
  padding-top: 6px;
}

@keyframes popoverIn {
  to { opacity: 1; transform: translateX(-50%) translateY(0); }
}

/* ============================================================
   UTILITY BUTTONS — ghost buttons, nearly invisible
   ============================================================ */
.ink-wash-nav .nav-utils {
  display: flex;
  align-items: center;
  gap: 2px;
  flex-shrink: 0;
}

.ink-wash-nav .util-btn {
  width: 32px;
  height: 32px;
  border: none;
  border-radius: 10px;
  background: transparent;
  color: var(--text-tertiary, #8C8578);
  font-size: 14px;
  cursor: pointer;
  transition: all 350ms var(--ink-ease);
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}

.ink-wash-nav .util-btn:hover {
  background: rgba(140,133,120,0.06);
  color: var(--text-secondary, #57534e);
}

.ink-wash-nav .util-btn svg {
  width: 16px;
  min-width: 16px;
  height: 16px;
}

/* ============================================================
   TOOL STRIP — contextual actions, browse-mode only
   ============================================================ */
.ink-wash-nav .tool-strip {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0 18px;
  height: 0;
  overflow: hidden;
  opacity: 0;
  border-top: none;
  transition: height var(--transition-slow), opacity var(--transition-smooth);
  position: relative;
  z-index: 2;
}

.ink-wash-nav .tool-strip::before {
  display: none;
}

.ink-wash-nav .tool-strip.visible {
  height: 42px;
  opacity: 1;
}

/* Tablet scroll: collapse tool strip, keep header row visible */
.ink-wash-nav .tool-strip.visible.scroll-collapsed {
  height: 0;
  opacity: 0;
  overflow: hidden;
  transition: height 120ms var(--ease-out), opacity 100ms ease;
}

.ink-wash-nav .tool-group {
  display: flex;
  align-items: center;
  gap: 6px;
}

.ink-wash-nav .tool-group + .tool-group {
  margin-left: 0;
  padding-left: 0;
  border-left: none;
}

.ink-wash-nav .tool-spacer { flex: 1; }

.ink-wash-nav .tool-btn {
  height: 28px;
  padding: 0 16px;
  border: none;
  border-radius: 8px;
  background: transparent;
  font-family: inherit;
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.01em;
  color: var(--text-secondary, #57534e);
  cursor: pointer;
  transition: color 350ms var(--ink-ease), font-weight 200ms ease;
  white-space: nowrap;
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 5px;
}

/* Inline SVG icons inside toolbar buttons */
.ink-wash-nav .tool-btn .btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.ink-wash-nav .tool-btn .btn-icon svg {
  width: 13px;
  height: 13px;
}
.ink-wash-nav .segment-pair .tool-btn .btn-icon svg {
  width: 11px;
  height: 11px;
}

/* Ink underline — grows from center on hover */
.ink-wash-nav .tool-btn::after {
  content: '';
  position: absolute;
  bottom: 2px;
  left: 50%;
  width: 60%;
  height: 1.5px;
  background: var(--text-secondary, #57534e);
  border-radius: 1px;
  transform: translateX(-50%) scaleX(0);
  transform-origin: center;
  transition: transform 350ms var(--ink-ease);
}

.ink-wash-nav .tool-btn:hover {
  color: var(--text-primary, #2C2C2C);
}

.ink-wash-nav .tool-btn:hover::after {
  transform: translateX(-50%) scaleX(1);
}

.ink-wash-nav .tool-btn:active {
  transform: scale(0.96) translateY(1px);
}

.ink-wash-nav .tool-btn.active {
  font-weight: 500;
  color: var(--accent, #3D5A80);
  background: rgba(61,90,128,0.08);
}

.ink-wash-nav .tool-btn.active::after {
  transform: translateX(-50%) scaleX(0);
}

.ink-wash-nav .tool-btn.active:hover {
  color: var(--text-primary, #2C2C2C);
}

/* Play button — ghost with chevron (和の感性: subtraction before addition) */
.ink-wash-nav .tool-btn-play {
  gap: 2px;
  display: inline-flex;
  align-items: center;
}
.ink-wash-nav .tool-btn-play .play-chevron {
  font-size: 8px;
  line-height: 1;
  opacity: 0.4;
  transition: transform 220ms cubic-bezier(0.16, 1, 0.3, 1), opacity 180ms ease;
  display: inline-block;
}
.ink-wash-nav .tool-btn-play:hover .play-chevron {
  opacity: 0.7;
}
.ink-wash-nav .tool-btn-play.dropdown-open {
  font-weight: 500;
  color: var(--text-primary, #2C2C2C);
}
.ink-wash-nav .tool-btn-play.dropdown-open .play-chevron {
  transform: rotate(180deg);
  opacity: 0.7;
}

/* Flip EN/JP — hidden until cards are revealed */
.ink-wash-nav .tool-btn.flip-btn-hidden {
  display: none;
}

/* Filter dot on filter button */
.ink-wash-nav .tool-btn .filter-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent, #3D5A80);
  display: inline-block;
  margin-left: 4px;
  opacity: 0;
  transition: opacity var(--transition-smooth), box-shadow var(--transition-smooth);
}

.ink-wash-nav .tool-btn.has-filters .filter-dot {
  opacity: 0.85;
  box-shadow: 0 0 6px rgba(61, 90, 128, 0.25);
}

/* Progress micro bar (gold kintsugi) */
.ink-wash-nav .progress-micro-bar {
  display: flex;
  width: 80px;
  height: 3px;
  border-radius: 1.5px;
  background: rgba(44,44,44,0.04);
  overflow: hidden;
  flex-shrink: 0;
}

.ink-wash-nav .micro-seg {
  height: 100%;
  transition: width 0.8s cubic-bezier(0.16, 1, 0.3, 1);
}

.ink-wash-nav .micro-seg-mastered {
  background: var(--kintsugi-gold, #C9A96E);
  opacity: 0.65;
  border-radius: 1.5px 0 0 1.5px;
}

.ink-wash-nav .micro-seg-practicing {
  background: var(--text-tertiary, #8C8578);
  opacity: 0.2;
}

/* Toolbar stats counts — dot + number + label */
.ink-wash-nav .stats-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  display: inline-block;
  flex-shrink: 0;
  margin-right: 3px;
}
.ink-wash-nav .stats-dot-known { background: var(--progress-green, #6B7F5C); opacity: 0.7; }
.ink-wash-nav .stats-dot-learning { background: var(--kintsugi-gold, #C9A96E); opacity: 0.7; }
.ink-wash-nav .stats-dot-new { background: var(--text-tertiary, #8C8578); opacity: 0.3; }

.ink-wash-nav .stats-num {
  font-size: 10px;
  font-weight: 500;
  color: var(--text-secondary, #57534e);
  font-variant-numeric: tabular-nums;
  margin-right: 2px;
}
.ink-wash-nav .stats-label {
  font-size: 10px;
  font-weight: 400;
  color: var(--text-tertiary, #8C8578);
  margin-right: 8px;
}

/* Segment pair — two or three mutually exclusive buttons */
.ink-wash-nav .segment-pair {
  display: flex;
  align-items: center;
  gap: 2px;
  background: rgba(44,44,44,0.025);
  border-radius: 8px;
  padding: 2px;
}

.ink-wash-nav .segment-pair .tool-btn {
  height: 24px;
  padding: 0 12px;
  font-size: 11px;
  border-radius: 6px;
  transition: color 250ms var(--ink-ease), background 250ms var(--ink-ease), font-weight 200ms ease, box-shadow 250ms ease;
}

.ink-wash-nav .segment-pair .tool-btn::after {
  display: none;
}

.ink-wash-nav .segment-pair .tool-btn.active {
  background: var(--card-surface, #FAFAF7);
  color: var(--text-primary, #2C2C2C);
  font-weight: 500;
  box-shadow: 0 1px 3px rgba(44,44,44,0.06);
}

.ink-wash-nav .segment-pair .tool-btn:not(.active):hover {
  color: var(--text-primary, #2C2C2C);
  background: rgba(44,44,44,0.02);
}

/* Tool divider — vertical separator between groups */
.ink-wash-nav .tool-divider {
  width: 1px;
  height: 18px;
  background: rgba(44,44,44,0.06);
  margin: 0 8px;
  flex-shrink: 0;
}

/* Direction toggle — appears next to Revise */
.ink-wash-nav .direction-toggle {
  height: 24px;
  padding: 0 10px;
  border: 1px solid rgba(44,44,44,0.08);
  border-radius: 6px;
  background: transparent;
  font-family: inherit;
  font-size: 10px;
  font-weight: 400;
  letter-spacing: 0.01em;
  color: var(--text-secondary, #57534e);
  cursor: pointer;
  white-space: nowrap;
  margin-left: 6px;
  transition: color 250ms ease, border-color 250ms ease, background 250ms ease, opacity 250ms ease;
}

.ink-wash-nav .direction-toggle:hover {
  color: var(--text-primary, #2C2C2C);
  border-color: rgba(44,44,44,0.15);
  background: rgba(44,44,44,0.02);
}

/* Word count in tool strip */
.ink-wash-nav .tool-word-count {
  font-size: 11px;
  color: var(--text-tertiary, #8C8578);
}

.ink-wash-nav .wc-number {
  font-family: 'Klee One', serif;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-secondary, #57534e);
}

.ink-wash-nav .wc-label {
  font-family: 'Inter', sans-serif;
  font-size: 11px;
  font-weight: 400;
  color: var(--text-tertiary, #8C8578);
}

/* ============================================================
   FLOWING TAB BAR (Ink Wash Strip)
   Hidden by default, revealed via Filter toggle button
   ============================================================ */

/* Visible when toggled */

/* Ink underline */

/* Status-specific ink colors */

/* Content filter ink */

/* Active state — dot-only indicator, no underline or wash */

/* Hover states */

/* Count badges */
.ink-wash-nav .tab-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: var(--radius-pill);
  font-size: 10px;
  font-weight: 500;
  line-height: 1;
  transition: all var(--transition-smooth);
}

/* Divider */
.ink-wash-nav .filter-divider {
  width: 1px;
  align-self: stretch;
  margin: 6px 4px;
  background: linear-gradient(180deg, transparent 10%, rgba(44,44,44,0.05) 40%, rgba(44,44,44,0.05) 60%, transparent 90%);
  flex-shrink: 0;
}

/* Chevron on content tabs */
.ink-wash-nav .tab-chevron {
  width: 14px;
  height: 14px;
  color: var(--text-secondary, #57534e);
  opacity: 0.4;
  transition: transform var(--transition-smooth), opacity var(--transition-smooth);
  flex-shrink: 0;
}

/* Active filter dots — sole indicator for active state */

/* Status dots — colored per mastery level */

/* ============================================================
   EXPANDING PANELS
   ============================================================ */

/* Panels with grid content need more height */

/* ============================================================
   CATEGORY GRID — multi-column tier1 layout (一覧 ichiran)
   All 23 categories visible at a glance, bento box model
   ============================================================ */

/* ============================================================
   FILTER ACTIVE CHIPS (below nav bar)
   ============================================================ */
.ink-wash-nav .filter-active-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 10px 18px 12px;
  border-top: none;
  align-items: center;
  position: relative;
}

/* When chips are inline in the toolbar */
.ink-wash-nav .filter-active-chips.toolbar-chips {
  flex: 1;
  flex-wrap: nowrap;
  overflow-x: auto;
  padding: 0 12px;
  gap: 5px;
  min-width: 0;
  scrollbar-width: none;  /* Firefox */
}
.ink-wash-nav .filter-active-chips.toolbar-chips::-webkit-scrollbar {
  display: none;
}

.ink-wash-nav .filter-active-chips::before {
  content: '';
  position: absolute;
  top: 0;
  left: 12%;
  right: 12%;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(44,44,44,0.04) 30%, rgba(44,44,44,0.04) 70%, transparent);
}
.ink-wash-nav .filter-active-chips.toolbar-chips::before {
  display: none;
}

.ink-wash-nav .filter-active-chips:empty {
  display: none;
}
/* Toolbar chips: stay visible as spacer even when empty */
.ink-wash-nav .filter-active-chips.toolbar-chips:empty {
  display: block;
}

/* Receipt chips — the catalog's ledger dress: washi, hairline, the gallery's
   3px radius. One chip for every axis; color appears only as a pigment dot
   where color is data (tier / politeness hues). */
.ink-wash-nav .filter-active-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 24px;
  padding: 0 8px 0 10px;
  border: 1px solid rgba(44,44,44,0.10);
  border-radius: 3px;
  background: var(--card-surface, #FAFAF7);
  font-family: inherit;
  font-size: 11.5px;
  white-space: nowrap;
  flex-shrink: 0;
  font-weight: 500;
  color: var(--text-secondary, #57534e);
  cursor: default;
  transition: border-color 350ms var(--ink-ease), opacity 350ms var(--ink-ease);
  animation: chipSlideIn 250ms ease;
}

.ink-wash-nav .filter-active-chip:hover {
  border-color: rgba(44,44,44,0.22);
}

/* Pigment dots — the chip's only color, mirrored from the panel's data hues. */
.ink-wash-nav .filter-active-chip:is(.chip-freq-tier-1, .chip-freq-tier-2,
    .chip-freq-tier-3, .chip-freq-tier-4, .chip-register-honorific,
    .chip-register-humble, .chip-register-casual, .chip-register-slang,
    .chip-register-rude)::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--chip-dot, #8C8578);
}
.ink-wash-nav .filter-active-chip.chip-freq-tier-1 { --chip-dot: #3a6438; }
.ink-wash-nav .filter-active-chip.chip-freq-tier-2 { --chip-dot: #5A7494; }
.ink-wash-nav .filter-active-chip.chip-freq-tier-3 { --chip-dot: #A88542; }
.ink-wash-nav .filter-active-chip.chip-freq-tier-4 { --chip-dot: #B8B0A4; }
.ink-wash-nav .filter-active-chip.chip-register-honorific,
.ink-wash-nav .filter-active-chip.chip-register-humble { --chip-dot: var(--color-accent); }
.ink-wash-nav .filter-active-chip.chip-register-casual { --chip-dot: #6b6256; }
.ink-wash-nav .filter-active-chip.chip-register-slang  { --chip-dot: var(--color-gold); }
.ink-wash-nav .filter-active-chip.chip-register-rude   { --chip-dot: #9c4f3f; }
/* Axis dots for the data-less axes — one hue per AXIS from existing tokens
   (never per-option): books indigo, word-type stone, topics moss; status
   wears the app's own mastery colors. The receipt row reads by type at a
   glance. */
.ink-wash-nav .filter-active-chip:is(.chip-textbook, .chip-pos, .chip-category,
    .chip-status-new, .chip-status-learning, .chip-status-coming,
    .chip-status-resting)::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--chip-dot, #8C8578);
}
.ink-wash-nav .filter-active-chip.chip-textbook { --chip-dot: var(--color-accent); }
.ink-wash-nav .filter-active-chip.chip-pos      { --chip-dot: var(--color-faint); }
.ink-wash-nav .filter-active-chip.chip-category { --chip-dot: var(--color-moss, #6B7F5C); }
/* The four locked states wear the wall's own state inks (2026-08-16, with the
   panel's 状 group). chip-status-known is GONE with the legacy three-state
   axis: 'known' lumped Resting and Coming back together, and the beam cannot
   print a dot for a state the product no longer names. */
.ink-wash-nav .filter-active-chip.chip-status-new      { --chip-dot: var(--color-faint, #B8B0A4); }
/* ONE MARK (desktop polish round 3, finding 12): New is a hollow ring wherever
   New is shown, as the panel's 状 row draws it (css/browse-sidebar.css):
   a 1.5px ring in the faint ink, never a filled dot. Silence has always
   meant new; a filled dot on the state most cards are in is decoration. */
.ink-wash-nav .filter-active-chip.chip-status-new::before {
  background: transparent;
  box-shadow: inset 0 0 0 1.5px var(--chip-dot);
}
.ink-wash-nav .filter-active-chip.chip-status-learning { --chip-dot: var(--color-amber, #A07850); }
.ink-wash-nav .filter-active-chip.chip-status-coming   { --chip-dot: var(--color-moss-bright, #5B8C5A); }
.ink-wash-nav .filter-active-chip.chip-status-resting  { --chip-dot: var(--color-moss, #6B7F5C); }
/* The register text tints from register-chip.css stay neutral in the beam. */
.ink-wash-nav :is(.chip-register-honorific, .chip-register-humble,
    .chip-register-casual, .chip-register-slang, .chip-register-rude) {
  color: var(--text-secondary, #57534e);
}

.ink-wash-nav .filter-active-chip .chip-remove {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: none;
  background: transparent;
  color: var(--text-secondary, #57534e);
  opacity: 0;
  font-size: 11px;
  cursor: pointer;
  /* named properties, never `all`: `all` animated the keyboard's ring in
     from a 3px text-coloured outline (round 3, the one ring lands crisp) */
  transition: opacity var(--transition-smooth), background-color var(--transition-smooth), color var(--transition-smooth);
  padding: 0;
  line-height: 1;
}

.ink-wash-nav .filter-active-chip:hover .chip-remove,
.ink-wash-nav .filter-active-chip:focus-within .chip-remove {
  opacity: 0.5;
}
/* the × a keyboard lands on shows itself whole (round 3: it sat at opacity
   0 until hovered, so Tab put the ring round nothing). Ink only, never the
   chip's geometry. */
.ink-wash-nav .filter-active-chip .chip-remove:focus-visible {
  opacity: 1;
}

.ink-wash-nav .filter-active-chip .chip-remove:hover {
  opacity: 1;
  background: rgba(44,44,44,0.08);
}


/* Excluded chips — hollow with bold left-border accent + brush batsu icon */
.ink-wash-nav .filter-active-chip.chip-excluded {
  background: transparent;
  border: 1px solid rgba(44,44,44,0.12);
  opacity: 0.72;
  transition: opacity 200ms ease;
}
.ink-wash-nav .filter-active-chip.chip-excluded:hover {
  opacity: 0.9;
}
/* Brush batsu icon */
.ink-wash-nav .filter-active-chip.chip-excluded .chip-text {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.ink-wash-nav .filter-active-chip.chip-excluded .chip-exclude-icon {
  display: block;
  flex-shrink: 0;
  color: #c45c3e;
}

/* Chip text — clickable to toggle include/exclude */
.ink-wash-nav .filter-active-chip .chip-text {
  cursor: pointer;
}

/* Clear all chips */
.ink-wash-nav .chip-clear-all {
  height: 26px;
  padding: 0 12px;
  border: none;
  border-radius: 8px;
  background: transparent;
  font-family: inherit;
  font-size: 11px;
  font-weight: 500;
  color: var(--text-tertiary, #8C8578);
  cursor: pointer;
  /* named properties, never `all` (the one ring lands crisp, round 3) */
  transition: background-color 350ms var(--ink-ease), color 350ms var(--ink-ease);
  margin-left: auto;
}

.ink-wash-nav .chip-clear-all:hover {
  background: rgba(140,133,120,0.06);
  color: var(--text-secondary, #57534e);
}

@keyframes chipSlideIn {
  from {
    opacity: 0;
    transform: scale(0.85) translateY(-4px);
  }
  to {
    opacity: 1;
    transform: scale(1) translateY(0);
  }
}

.ink-wash-nav .filter-active-chip.removing {
  animation: chipSlideOut 200ms ease forwards;
}

@keyframes chipSlideOut {
  to {
    opacity: 0;
    transform: scale(0.85) translateY(-4px);
  }
}

/* Short tab labels (480px and below) */

/* ============================================================
   NAV COLLAPSED — filter strip + expand panels auto-hide
   after filter selection. Header + tool strip + chips stay.
   ============================================================ */
.ink-wash-nav .nav-summary-pill { display: none; }

/* ============================================================
   GRID MARGIN — spacing below unified fixed header
   Driven by --nav-bar-total-height CSS variable set from JS
   ============================================================ */
body.grid-mode .grid-container {
  margin-top: calc(var(--nav-bar-total-height, 80px) + 24px);
  transition: margin-top 250ms var(--ease-out);
}

/* Desktop only: reclaim nav space when hidden (transform-based, no reflow issues).
   Mobile keeps constant margin — nav hides via top offset, no margin change needed. */
@media (min-width: 769px) {
  body.grid-mode.nav-is-hidden .grid-container {
    margin-top: 24px;
  }
}

/* ============================================================
   ACCESSIBILITY
   ============================================================ */

.ink-wash-nav .tool-btn:focus-visible,
.ink-wash-nav .mode-btn:focus-visible,
.ink-wash-nav .util-btn:focus-visible {
  outline: 2px solid var(--accent, #3D5A80);
  outline-offset: 2px;
}
/* ONE RING (desktop polish round 3, finding 10): every control on the beam
   and its chips row shows the keyboard's focus as the app's one ring, 2px
   indigo 2px off the control, and nothing else: base.css adds a 4px 15%
   halo to every focused button and [role=button], a second frame round
   the first. (+ Filter's pressed underline is an inset shadow too; its
   rule below keeps it under the ring.) Desktop only: the phone's beam is
   another product. */
@media (min-width: 769px) {
  .ink-wash-nav :is(button, a[href], [role="button"], [role="tab"]):focus-visible {
    outline: 2px solid var(--color-accent, #3D5A80);
    outline-offset: 2px;
    box-shadow: none;
  }
}

/* ============================================================
   DESKTOP SIDEBAR — the browse sidebar owns filtering on desktop
   (the old row-3 filter strip + expand panels were removed 2026-07-11)
   ============================================================ */
@media (min-width: 769px) {
  /* Hide standalone filter chips row on desktop — but keep toolbar-inline chips */
  .ink-wash-nav .filter-active-chips:not(.toolbar-chips) {
    display: none !important;
  }

  /* Hide mode-selector on desktop (mobile-only class) */
  .ink-wash-nav .mode-selector.mobile-only {
    display: none;
  }

  /* Position relative for popup children */
  .nav-bar-inner {
    position: relative;
  }
}

/* ============================================================
   RESPONSIVE: MOBILE (<= 768px)
   ============================================================ */
@media (max-width: 768px) {

  /* ============================================================
     MOBILE NAV — Bottom Sheet Pattern
     Fixed header + action strip + filter strip always visible.
     Content filters (Textbook/Category/POS) open in bottom sheet.
     ============================================================ */

  /* --- Nav container --- */
  .ink-wash-nav {
    padding: 0 8px;
  }

  /* Mobile scroll-hide: use top (not transform) so position:fixed children
     (filter sheet, backdrop, search overlay) stay viewport-anchored.
     transform creates a containing block per CSS spec, breaking position:fixed
     on children. top offset does not. */
  .ink-wash-nav {
    transition: none; /* Instant — animating top triggers layout per frame */
  }
  .ink-wash-nav.nav-hidden {
    transform: none; /* Override desktop translateY; top set by JS */
  }

  .nav-bar-inner {
    margin: 6px auto 0;
    border-radius: var(--radius-panel);
    max-width: 100%;
    border: none;
    overflow: visible;
    transition: box-shadow 300ms ease;
  }

  /* Paper-resting-on-content bottom edge */
  .nav-bar-inner::after {
    content: '';
    position: absolute;
    bottom: -8px;
    left: 0;
    right: 0;
    height: 8px;
    background: linear-gradient(180deg, rgba(44,44,44,0.04) 0%, rgba(44,44,44,0.015) 40%, transparent 100%);
    pointer-events: none;
    z-index: 1;
  }

  /* Header shadow on scroll */
  .ink-wash-nav.has-shadow .nav-bar-inner {
    box-shadow: 0 2px 12px rgba(44,44,44,0.06), 0 1px 3px rgba(44,44,44,0.04);
  }

  /* --- Header row: ~48px, always visible --- */
  .ink-wash-nav .header-row {
    height: 48px;
    padding: 0 16px;
    gap: 10px;
    flex-wrap: nowrap;
    align-items: center;
    position: relative;
    z-index: 5;
  }

  /* Brand: logo + KOTOBA text (no toggle chevron) */
  .ink-wash-nav .nav-brand {
    order: 1;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 8px;
    -webkit-tap-highlight-color: transparent;
  }
  .ink-wash-nav .nav-brand::after { display: none; }
  .ink-wash-nav .brand-text {
    display: inline;
    font-size: 10.5px; /* size-only override of .kotoba-wordmark--nav (§8 mobile-nav scale) */
  }
  .ink-wash-nav .brand-logo { width: 26px; height: 26px; border-radius: 50%; }
  .ink-wash-nav .header-spacer { display: block; flex: 1; order: 2; }

  /* Mobile word count in header */
  .ink-wash-nav .mobile-word-count {
    order: 3;
    font-size: 11px;
    color: var(--text-tertiary, #8C8578);
    white-space: nowrap;
  }
  .ink-wash-nav .mobile-word-count .wc-number {
    font-family: 'Klee One', serif;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-secondary, #57534e);
  }


  /* Nav utils */
  .ink-wash-nav .nav-utils { order: 6; margin-left: 0; }
  .ink-wash-nav .nav-utils .util-btn.hide-mobile { display: none; }

  /* --- Hide mode selector on mobile (no Browse/Focus/Video/Voice/Quiz buttons) --- */
  .ink-wash-nav .mode-selector { display: none !important; }

  /* --- Expand zone: collapses as single unit on scroll --- */
  .ink-wash-nav .nav-expand-zone {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    max-height: 86px; /* tool-strip 36px + status-row ~50px */
    opacity: 1;
    transition: max-height 100ms ease-out, opacity 100ms ease-out;
  }
  .ink-wash-nav .nav-expand-zone.scroll-hidden {
    max-height: 0;
    opacity: 0;
  }

  /* --- Override desktop nav-collapsed on mobile --- */
  .ink-wash-nav.nav-collapsed .filter-active-chips {
    display: flex;
  }

  /* --- Hide inline expand panels on mobile (content is in bottom sheet) --- */

  /* --- Action strip (tool-strip): ~36px, always visible --- */
  .ink-wash-nav .tool-strip {
    height: 36px !important;
    padding: 0 16px !important;
    gap: 4px;
  }
  .ink-wash-nav .tool-strip .tool-btn {
    font-size: 12px;
    padding: 0 12px;
    height: 26px;
  }
  .ink-wash-nav .tool-strip .tool-word-count { display: none; }
  .ink-wash-nav .tool-strip .progress-micro-bar { display: none; }
  .ink-wash-nav .tool-strip .tool-spacer { display: block; flex: 1; }
  .ink-wash-nav .tool-btn-play { display: none !important; }
  .ink-wash-nav .filter-pill-row { display: none !important; }

  /* Quiz button: push to right edge */
  .ink-wash-nav .tool-group-meta {
    margin-left: auto;
  }
  .ink-wash-nav .quiz-action-btn {
    display: inline-flex !important;
  }

  /* --- Mobile status pills + filter chips row --- */
  .ink-wash-nav .mobile-status-row {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 2px 16px 6px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    flex-wrap: nowrap;
  }
  .ink-wash-nav .mobile-status-row::-webkit-scrollbar { display: none; }
  /* Scroll-hide is now on .nav-expand-zone wrapper (single-unit collapse) */

  .ink-wash-nav .status-pill {
    height: 28px;
    padding: 0 10px;
    border: 1px solid rgba(44,44,44,0.07);
    border-radius: 999px;
    font-size: 12px;
    font-weight: 500;
    white-space: nowrap;
    flex-shrink: 0;
    background: transparent;
    color: var(--text-secondary, #57534e);
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-family: 'Inter', -apple-system, sans-serif;
    -webkit-tap-highlight-color: transparent;
    transition: all 200ms ease;
    cursor: pointer;
  }
  .ink-wash-nav .status-pill:active { transform: scale(0.96); }
  .ink-wash-nav .status-pill[data-status="new"].active {
    background: rgba(91,123,140,0.1);
    color: #5B7B8C;
    border-color: rgba(91,123,140,0.25);
    font-weight: 600;
  }
  .ink-wash-nav .status-pill[data-status="learning"].active {
    background: rgba(160,120,80,0.1);
    color: var(--color-amber);
    border-color: rgba(160,120,80,0.25);
    font-weight: 600;
  }
  .ink-wash-nav .status-pill[data-status="known"].active {
    background: rgba(123,139,111,0.1);
    color: #7B8B6F;
    border-color: rgba(123,139,111,0.25);
    font-weight: 600;
  }

  .ink-wash-nav .mobile-filter-chips {
    display: none;
  }

  /* --- Filter strip: hidden on mobile (status in mobile-status-row, content in sheet menu) --- */

  /* Gradient separator above filter pills */

  /* Filter tabs as pills */

  /* Status pills active states */

  /* Content filter pills: accent highlight when expanded/has-selection */

  /* Chevron rotation when expanded */

  /* Filter divider */
  .ink-wash-nav .filter-divider {
    width: 1px;
    height: 20px;
    background: linear-gradient(180deg, transparent 10%, rgba(44,44,44,0.06) 50%, transparent 90%);
    flex-shrink: 0;
    align-self: center;
    margin: 0;
  }

  /* --- Mobile inline expand row: hidden (content filters moved to sheet menu) --- */
  /* Hide inline row when filters are collapsed (scroll auto-hide) */

  /* Tab count badge */
  .ink-wash-nav .tab-count {
    min-width: 16px;
    height: 16px;
    font-size: 10px;
    font-weight: 500;
    opacity: 0.6;
    padding: 0 4px;
    border-radius: 999px;
    background: rgba(44,44,44,0.04);
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  /* --- Toolbar chips: hidden on mobile (mirrored in mobile-status-row) --- */
  .ink-wash-nav .filter-active-chips.toolbar-chips {
    display: none !important;
  }

  /* --- Chips: horizontal scroll row (always visible when active) --- */
  .ink-wash-nav .filter-active-chips {
    padding: 6px 16px 6px;
    position: relative;
    display: none;
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    gap: 6px;
    align-items: center;
  }
  .ink-wash-nav .filter-active-chips::before {
    display: none;
  }
  .ink-wash-nav .filter-active-chips::-webkit-scrollbar { display: none; }
  .ink-wash-nav .filter-active-chips.visible,
  .ink-wash-nav .filter-active-chips:not(:empty) {
    display: flex;
  }

  .ink-wash-nav .filter-active-chip {
    white-space: nowrap;
    flex-shrink: 0;
    animation: chipSlideIn 250ms ease;
  }
  .ink-wash-nav .filter-active-chip.just-added {
    animation: mobileChipFlashIn 600ms ease;
  }
  .ink-wash-nav .filter-active-chip.chip-excluded {
    border: 1px solid rgba(44,44,44,0.12);
  }
  .ink-wash-nav .filter-active-chip .chip-text {
    -webkit-tap-highlight-color: transparent;
  }

  /* Touch-friendly chip remove */
  .ink-wash-nav .filter-active-chip .chip-remove {
    opacity: 0.45;
    min-width: 44px;
    min-height: 44px;
    padding: 14px;
    margin: -14px -10px -14px -4px;
    position: relative;
    background: transparent !important;
    -webkit-tap-highlight-color: transparent;
  }
  .ink-wash-nav .filter-active-chip .chip-remove:active { opacity: 0.8; }

  .ink-wash-nav .chip-clear-all {
    white-space: nowrap;
    flex-shrink: 0;
    -webkit-tap-highlight-color: transparent;
  }
  .ink-wash-nav .chip-clear-all.confirming {
    animation: mobileClearShake 300ms ease;
    color: #B85C3B;
  }

  /* --- Bottom sheet backdrop --- */
  .ink-wash-nav .mobile-sheet-backdrop {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 100;
    background: rgba(44,44,44,0.15);
    opacity: 0;
    pointer-events: none;
    transition: opacity 250ms ease;
  }
  .ink-wash-nav .mobile-sheet-backdrop.active {
    opacity: 1;
    pointer-events: auto;
  }

  /* --- Bottom sheet --- */
  .ink-wash-nav .mobile-filter-sheet {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 101;
    height: 65vh;
    background: var(--card-surface, #FAFAF7);
    border-radius: 16px 16px 0 0;
    box-shadow: 0 -4px 24px rgba(44,44,44,0.08);
    transform: translateY(100%);
    transition: transform 250ms cubic-bezier(0.32, 0.72, 0, 1);
    display: flex;
    flex-direction: column;
    pointer-events: auto;
  }
  .ink-wash-nav .mobile-filter-sheet.open {
    transform: translateY(0);
    transition-duration: 350ms;
  }

  /* Drag handle — ceramic feel */
  .ink-wash-nav .sheet-drag-handle {
    display: flex;
    justify-content: center;
    padding: 14px 0 10px;
    flex-shrink: 0;
    cursor: grab;
  }
  .ink-wash-nav .sheet-handle-pill {
    width: 32px;
    height: 3.5px;
    background: rgba(140,133,120,0.18);
    border-radius: 2px;
  }

  /* Sheet content (scrollable) */

  /* Sheet section label — carved seal inscription, not screaming header */

  /* Sheet pills — same tokens as desktop expand panels */

  /* Back pill in sheet */

  /* Grid cells in sheet (category tier1, textbook lessons) */

  /* Textbook lessons: 1-column full-width rows */

  /* --- Sheet menu rows (Browse entry point) --- */
  /* Organic separator — ink wash, not ruled line */
  /* Active filter count — gold wash chip, not loud accent badge */

  /* Level 1 drill-down rows: lighter than top menu (hierarchy through weight) */

  /* --- Active filter chips inside Browse sheet --- */
  /* Textbook chips — indigo tint */
  /* Category chips — warm gold tint (default) */
  /* POS chips — muted green tint */

  /* Sheet auto-height for menu layer */
  .ink-wash-nav .mobile-filter-sheet[data-section="menu"] {
    height: auto;
    min-height: 180px;
    max-height: 65vh;
  }

  /* --- Sheet back row — quiet wayfinding, not a button --- */

  /* --- Sheet toggle row — selectable items --- */
  /* Organic separator */
  /* Selected state: ink-dark label + gold left bar + gold checkmark */

  /* --- Menu row meta (word count) --- */

  /* --- Mobile search overlay --- */
  .ink-wash-nav .mobile-search-overlay {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 150;
    background: rgba(240,237,232,0.97);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    padding: 52px 16px 0;
    opacity: 0;
    pointer-events: none;
    transition: opacity 250ms ease;
  }
  .ink-wash-nav .mobile-search-overlay.open {
    opacity: 1;
    pointer-events: auto;
  }
  .ink-wash-nav .mobile-search-bar {
    display: flex;
    align-items: center;
    gap: 10px;
    height: 48px;
    padding: 0 16px;
    background: var(--card-surface, #FAFAF7);
    border-radius: 14px;
    box-shadow: 0 2px 8px rgba(44,44,44,0.06);
    border: 1px solid rgba(44,44,44,0.06);
  }
  .ink-wash-nav .mobile-search-bar svg {
    width: 16px;
    height: 16px;
    color: var(--text-tertiary, #8C8578);
    flex-shrink: 0;
  }
  .ink-wash-nav .mobile-search-input {
    flex: 1;
    height: 100%;
    border: none;
    background: transparent;
    font-family: 'Inter', sans-serif;
    font-size: 15px;
    color: var(--text-primary, #2C2C2C);
    outline: none;
  }
  .ink-wash-nav .mobile-search-input::placeholder {
    color: var(--text-tertiary, #8C8578);
  }
  .ink-wash-nav .mobile-search-cancel {
    border: none;
    background: transparent;
    font-family: 'Inter', sans-serif;
    font-size: 14px;
    font-weight: 500;
    color: var(--accent, #3D5A80);
    cursor: pointer;
    padding: 8px 4px;
    -webkit-tap-highlight-color: transparent;
  }
  .ink-wash-nav .mobile-search-hint {
    padding: 20px 4px;
    font-size: 13px;
    color: var(--text-tertiary, #8C8578);
    text-align: center;
  }
  .ink-wash-nav .mobile-search-results {
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    max-height: calc(100dvh - 140px);
    padding: 4px 0;
  }
  .ink-wash-nav .mobile-search-result-item {
    display: flex;
    align-items: baseline;
    gap: 8px;
    width: 100%;
    padding: 14px 16px;
    border: none;
    background: transparent;
    text-align: left;
    font-family: inherit;
    cursor: pointer;
    border-bottom: 1px solid rgba(44,44,44,0.04);
    -webkit-tap-highlight-color: transparent;
  }
  .ink-wash-nav .mobile-search-result-item:active {
    background: rgba(44,44,44,0.04);
  }
  .ink-wash-nav .msr-japanese {
    font-family: 'Klee One', serif;
    font-size: 18px;
    color: var(--text-primary, #2C2C2C);
    flex-shrink: 0;
  }
  .ink-wash-nav .msr-kanji {
    font-family: 'Klee One', serif;
    font-size: 14px;
    color: var(--text-secondary, #57534e);
    flex-shrink: 0;
  }
  .ink-wash-nav .msr-english {
    font-size: 13px;
    color: var(--text-secondary, #57534e);
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .ink-wash-nav .msr-pos {
    font-size: 10px;
    color: var(--text-tertiary, #8C8578);
    background: rgba(44,44,44,0.04);
    padding: 2px 6px;
    border-radius: 4px;
    flex-shrink: 0;
  }
  .ink-wash-nav .mobile-search-empty {
    padding: 32px 16px;
    text-align: center;
    font-size: 14px;
    color: var(--text-tertiary, #8C8578);
  }

  /* --- Hide desktop-only elements --- */
  .ink-wash-nav .tool-btn.hide-mobile,
  .ink-wash-nav .util-btn.hide-mobile,
  .ink-wash-nav .hide-mobile {
    display: none !important;
  }

  /* --- Hide legacy elements --- */
  .ink-wash-nav .compact-btn,
  .ink-wash-nav .mobile-filter-dot,
  .ink-wash-nav .nav-summary-pill {
    display: none;
  }

  /* --- Grid margin adjustment --- */
  body.grid-mode .grid-container {
    margin-top: calc(var(--nav-bar-total-height, 120px) + 16px);
    /* Margin stays constant on mobile — nav hides via top offset,
       no margin change, no scroll compensation needed. */
  }

  /* --- Mobile-only keyframes --- */
  @keyframes mobileChipFlashIn {
    0% { opacity: 0; transform: scale(0.85) translateY(-4px); }
    30% { opacity: 1; transform: scale(1.05) translateY(0); }
    50% { opacity: 0.7; }
    70% { opacity: 1; }
    100% { opacity: 1; transform: scale(1) translateY(0); }
  }

  @keyframes mobileClearShake {
    0%, 100% { transform: translateX(0); }
    15% { transform: translateX(-3px); }
    30% { transform: translateX(3px); }
    45% { transform: translateX(-2px); }
    60% { transform: translateX(2px); }
    75% { transform: translateX(-1px); }
    90% { transform: translateX(1px); }
  }

  /* ============================================================
     MOBILE SETTINGS SHEET — bottom sheet for settings on mobile
     ============================================================ */
  .ink-wash-nav .mobile-settings-sheet {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 101;
    background: var(--card-surface, #FAFAF7);
    border-radius: 16px 16px 0 0;
    box-shadow: 0 -4px 24px rgba(44,44,44,0.08);
    transform: translateY(100%);
    transition: transform 250ms cubic-bezier(0.32, 0.72, 0, 1);
    display: flex;
    flex-direction: column;
    pointer-events: auto;
  }
  .ink-wash-nav .mobile-settings-sheet.open {
    transform: translateY(0);
    transition-duration: 350ms;
  }

  /* Section spacing */
  .ink-wash-nav .mobile-settings-section {
    padding: 16px 0;
  }
  .ink-wash-nav .mobile-settings-section + .mobile-settings-section {
    border-top: 1px solid rgba(140,133,120,0.08);
  }

  /* Section labels — carved seal inscription */
  .ink-wash-nav .mobile-settings-label {
    display: block;
    font-size: 10px;
    font-weight: 500;
    color: var(--text-tertiary, #8C8578);
    text-transform: uppercase;
    letter-spacing: 0.12em;
    margin-bottom: 14px;
  }

  /* Display mode — segmented control */
  .ink-wash-nav .mobile-settings-display-mode {
    display: flex;
    gap: 0;
    background: rgba(44,44,44,0.03);
    border-radius: 10px;
    padding: 3px;
  }
  .ink-wash-nav .mobile-settings-display-mode .segment-btn {
    flex: 1;
    padding: 10px 16px;
    font-size: 14px;
    font-family: 'Inter', -apple-system, sans-serif;
    font-weight: 500;
    border: none;
    border-radius: 8px;
    background: transparent;
    color: var(--text-tertiary, #8C8578);
    cursor: pointer;
    transition: all 200ms ease;
    -webkit-tap-highlight-color: transparent;
    text-align: center;
    line-height: 1.3;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .ink-wash-nav .mobile-settings-display-mode .segment-btn.active {
    background: var(--card-surface, #FAFAF7);
    color: var(--text-primary, #2C2C2C);
    box-shadow: 0 1px 3px rgba(44,44,44,0.06), 0 1px 2px rgba(44,44,44,0.04);
  }
  .ink-wash-nav .mobile-settings-display-mode .segment-btn:active {
    transform: scale(0.97);
  }

  /* Reset progress */
  .ink-wash-nav .mobile-settings-reset-btn {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 12px 4px;
    font-size: 15px;
    font-family: 'Inter', -apple-system, sans-serif;
    color: var(--text-secondary, #57534e);
    background: none;
    border: none;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .ink-wash-nav .mobile-settings-reset-btn:active {
    opacity: 0.7;
  }
  .ink-wash-nav .mobile-settings-reset-icon {
    font-size: 16px;
    color: var(--text-tertiary, #8C8578);
  }

  /* Two-step confirm */
  .ink-wash-nav .mobile-settings-reset-confirm {
    display: none;
    padding: 4px 0;
  }
  .ink-wash-nav .mobile-settings-reset-group.confirming .mobile-settings-reset-btn {
    display: none;
  }
  .ink-wash-nav .mobile-settings-reset-group.confirming .mobile-settings-reset-confirm {
    display: block;
  }
  .ink-wash-nav .mobile-settings-reset-label {
    display: block;
    font-size: 14px;
    color: var(--text-secondary, #57534e);
    text-align: center;
    margin-bottom: 12px;
  }
  .ink-wash-nav .mobile-settings-reset-buttons {
    display: flex;
    gap: 10px;
  }
  .ink-wash-nav .mobile-settings-reset-yes,
  .ink-wash-nav .mobile-settings-reset-no {
    flex: 1;
    padding: 12px 16px;
    border-radius: 10px;
    background: none;
    font-size: 14px;
    font-family: inherit;
    font-weight: 500;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .ink-wash-nav .mobile-settings-reset-yes {
    border: 1px solid var(--color-amber-deep);
    color: var(--color-amber-deep);
  }
  .ink-wash-nav .mobile-settings-reset-yes:active {
    background: rgba(180, 83, 9, 0.08);
  }
  .ink-wash-nav .mobile-settings-reset-no {
    border: 1px solid rgba(44,44,44,0.10);
    color: var(--text-secondary, #57534e);
  }
  .ink-wash-nav .mobile-settings-reset-no:active {
    background: rgba(44,44,44,0.04);
  }

  /* Done state */
  .ink-wash-nav .mobile-settings-reset-group.done .mobile-settings-reset-btn,
  .ink-wash-nav .mobile-settings-reset-group.done .mobile-settings-reset-confirm {
    display: none;
  }
  .ink-wash-nav .mobile-settings-reset-group.done::after {
    content: 'Done';
    display: block;
    text-align: center;
    padding: 12px;
    font-size: 14px;
    color: var(--status-mastered-vivid, #5B9A6F);
    font-weight: 600;
  }
}

/* Desktop: hide mobile-only elements */
@media (min-width: 769px) {

  /* Expand zone is transparent passthrough on desktop */
  .ink-wash-nav .nav-expand-zone {
    display: contents;
  }
}

/* Category grid: 3 columns on narrow desktops */

/* No 480px breakpoint — filter strip scrolls horizontally,
   so full labels work at all mobile widths. */


/* ============================================================
   FILTER PILL ROW (Row 3)
   Shows active filter pills + "Add filter" button on desktop
   ============================================================ */
.ink-wash-nav .filter-pill-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 20px 8px;
  min-height: 32px;
}

.ink-wash-nav .filter-pills-scroll {
  display: flex;
  align-items: center;
  gap: 5px;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  flex-shrink: 1;
  min-width: 0;
}

.ink-wash-nav .filter-pills-scroll::-webkit-scrollbar { display: none; }

.ink-wash-nav .filter-pills-scroll .filter-active-chip {
  white-space: nowrap;
  flex-shrink: 0;
}

.ink-wash-nav .filter-add-btn {
  flex-shrink: 0;
  height: 28px;
  padding: 0 12px;
  border: none;
  border-radius: 8px;
  background: rgba(44,44,44,0.03);
  font-family: inherit;
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.01em;
  color: var(--text-tertiary, #8C8578);
  cursor: pointer;
  transition: color 350ms var(--ink-ease), background 200ms ease;
  white-space: nowrap;
}

.ink-wash-nav .filter-add-btn:hover {
  color: var(--text-secondary, #57534e);
  background: rgba(44,44,44,0.05);
}

.ink-wash-nav .filter-add-btn.has-filters {
  color: var(--text-secondary, #57534e);
}


/* (DECK BUTTONS — the quiet pill dress for .deck-btn / .deck-label /
   .deck-sub, plus the .review-subtab* / .subtab-count pair that split the
   Review deck into review-vs-refresh — RETIRED 2026-08-16 with the second
   beam row. No element in the app carries any of those classes any more:
   the four status decks left with #browseSubrow (browsing is looking, not
   studying), and the review/refresh split had already gone structurally
   unreachable on 2026-07-14. Do NOT resurrect this dress for a new counter
   — status browse deliberately lives nowhere; Practice answers debt with a
   question, not a filter. The under-beam LINE the decks stood on survives
   as .browse-subrow, which now dresses only the 稽古 walk's lintel — see
   the "the row is gone, the line remains" note further down this file. */

/* ============================================================
   今日 TODAY GROUP
   The header here described the tool strip's 今日 prefix standing at the head
   of the four status-deck filters, counts as the buttons themselves. That row
   is gone (the decks retired 2026-08-16, browsing is looking not studying),
   and the 今日 prefix itself had already become the beam's Practice path-tab
   (#todaySessionBtn, .path-tab) well before it.
   ⚠️ .today-prefix* / .today-sep therefore have NO emitter anywhere in js/ or
   index.html — they were already orphaned when this slice arrived and are left
   standing here on purpose, not overlooked: retiring them is its own audit, not
   this one's. ⚠️ SAME FOR .grid-session-line .gfv-en further down — its only
   writer is maybeShowSessionLine() in js/grid-mode.js, whose one call site has
   been commented out since 2026-06-15. NOTHING IN THIS BLOCK IS LIVE: do not
   read a rule here as proof a surface still paints.
   ============================================================ */
.ink-wash-nav .today-prefix {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  margin-right: 4px;
  /* It was a real button (it opened today's mixed-sequence session) and spoke
     the same quiet language as the status-deck buttons that stood beside it:
     no new visual idiom, just a subtle hover + active wash. Both those
     neighbours are gone — the decks with the second beam row (2026-08-16),
     this button into the beam's Practice tab before them. */
  border: none;
  background: transparent;
  font-family: inherit;
  padding: 3px 8px;
  border-radius: 8px;
  cursor: pointer;
  transition: background 0.2s ease;
}

.ink-wash-nav .today-prefix:hover {
  background: rgba(44, 44, 44, 0.03);
}

.ink-wash-nav .today-prefix.active {
  background: rgba(44, 44, 44, 0.04);
}

.ink-wash-nav .today-prefix:focus-visible {
  outline: 2px solid var(--color-accent, #3D5A80);
  outline-offset: 1px;
}

/* 今日 session header whisper above the sequence (reuses the first-visit
   line look; just a touch tighter so it reads as a section label).
   ⚠️ NO EMITTER — maybeShowSessionLine() is the only writer of the class and
   its one call site has been commented out since 2026-06-15 (the count rides
   the beam instead). Pre-existing; retiring it is its own audit. */
.grid-session-line .gfv-en {
  color: var(--text-secondary, #57534e);
}

.ink-wash-nav .today-prefix-jp {
  font-family: var(--font-jp, 'Klee One', sans-serif);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--color-ink, #2C2C2C);
}

.ink-wash-nav .today-prefix-en {
  font-size: 9.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-tertiary, #8C8578);
}

.ink-wash-nav .today-sep {
  color: rgba(44, 44, 44, 0.22);
  font-size: 11px;
  margin: 0 -2px;
}

/* (.deck-num — the status decks' tabular count — RETIRED 2026-08-16 with
   the decks themselves. The beam's one surviving number is the walk
   lintel's .n, dressed further down this file.) */


/* ============================================================
   SESSION COMPLETE OVERLAY
   ============================================================ */
.session-complete-overlay {
  position: fixed;
  inset: 0;
  z-index: 9000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(240, 237, 232, 0.6);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  opacity: 0;
  transition: opacity 0.4s var(--ink-ease, ease);
}

.session-complete-overlay.visible {
  opacity: 1;
}

.session-complete-card {
  background: var(--color-card);
  border-radius: 16px;
  padding: 40px 48px;
  max-width: 380px;
  width: 90%;
  text-align: center;
  box-shadow: 0 4px 24px rgba(44,44,44,0.08), 0 1px 4px rgba(44,44,44,0.04);
  transform: translateY(12px);
  transition: transform 0.4s var(--ease-out, ease);
}

.session-complete-overlay.visible .session-complete-card {
  transform: translateY(0);
}

.sc-heading {
  font-family: 'Klee One', serif;
  font-size: 24px;
  color: var(--color-ink);
  margin-bottom: 4px;
}

.sc-subheading {
  font-size: 13px;
  color: var(--color-faint);
  margin-bottom: 28px;
}

.sc-stats {
  background: rgba(44,44,44,0.02);
  border-radius: 12px;
  padding: 16px 20px;
  margin-bottom: 28px;
}

.sc-stat-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 0;
}

.sc-stat-row.sc-stat-border {
  border-top: 1px solid rgba(44,44,44,0.05);
  border-bottom: 1px solid rgba(44,44,44,0.05);
}

.sc-stat-label { font-size: 14px; }
.sc-stat-label.sc-known { color: var(--color-moss); }
.sc-stat-label.sc-learning { color: var(--color-accent); }
.sc-stat-label.sc-seen { color: var(--color-faint); }

.sc-stat-value {
  font-size: 20px;
  font-weight: 600;
  color: var(--color-ink);
}

.sc-btn {
  display: block;
  width: 100%;
  padding: 14px;
  border: none;
  border-radius: 12px;
  font-size: 16px;
  font-family: 'Klee One', serif;
  cursor: pointer;
  transition: all 0.2s ease;
  margin-bottom: 8px;
}

.sc-btn-sub {
  display: block;
  font-size: 12px;
  font-family: Inter, sans-serif;
  opacity: 0.7;
  margin-top: 2px;
}

.sc-btn-primary {
  background: var(--color-accent);
  color: white;
}

.sc-btn-primary:hover { background: #34506F; }

.sc-btn-secondary {
  background: rgba(44,44,44,0.04);
  color: var(--color-ink);
}

.sc-btn-secondary:hover { background: rgba(44,44,44,0.07); }

.sc-btn-ghost {
  background: transparent;
  color: var(--color-faint);
  margin-bottom: 0;
}

.sc-btn-ghost:hover { color: var(--color-ink); }


/* ============================================================
   HIDE/SHOW + LANGUAGE TOGGLE BUTTON OVERRIDES
   ============================================================ */
.ink-wash-nav .tool-group-hide {
  display: flex;
  align-items: center;
  gap: 2px;
}

#hideToggleBtn,
#langToggleBtn {
  font-size: 12px;
  min-width: auto;
  padding: 3px 8px;
}

#langToggleBtn {
  font-weight: 600;
  color: var(--color-accent);
}

/* ============================================================
   REDUCED MOTION
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .ink-wash-nav,
  .ink-wash-nav *,
  .ink-wash-nav *::before,
  .ink-wash-nav *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }

  .ink-wash-nav .brush-stroke { display: none; }
}

/* =============================================================================
   WALL, NOT FURNITURE — chrome = the stone the paintings hang on
   (Treatment A, owner-approved 2026-06-11. Desktop-scoped: the mobile nav
   keeps its own material rules below 769px.)
   The nav stops being a floating white card: a full-bleed band of the SAME
   composited wall tone (body bg under the seasonal veil — chrome must paint
   the composite itself or it reads a shade lighter than the wall), one ink
   hairline as the lintel. No radius, no shadow, no grain — the wall owns the
   texture budget.
   ============================================================================= */
@media (min-width: 769px) {
  /* The BAND (full-bleed stone + lintel) lives on the fixed outer element;
     the inner keeps syncNavWidth's inline max-width (= the wall's row width)
     and re-centers with margin:auto so the controls track the wall on any
     window width (owner round 3: content pinned left on wide screens). */
  .ink-wash-nav {
    padding: 0;
    background: var(--room-ground);
    border-bottom: 1px solid rgba(44, 44, 44, 0.10);  /* the lintel hairline */
  }

  .nav-bar-inner {
    margin: 0 auto;
    background: transparent;
    background-image: none;
    border-radius: 0;
    box-shadow: none;
    border: none;
  }

  /* Content aligns to the painting edges: the wall's cards inset their faces
     by --wall-pad (8px), so the brand and the first painting share a left
     edge. */
  .ink-wash-nav .header-row { height: 58px; padding: 0 8px; }
  .ink-wash-nav .tool-strip { padding: 0 8px; }

  /* SIDE-PANEL STATES: ONE GAP (desktop polish round 3, finding 7). The band
     is the same stone as the panel column, so it stays flush to it; its ROW
     keeps 24px off whichever panel is open (40px above 1440, as the wall
     does), the brand 24px off the filter panel's edge and the ⋮ 24px off
     the rail's (at 1280 they stood 8px and 56px:
     this rule set 0 for both, and the rail's own rule in
     css/browse-sidebar.css loaded later and won with 40px, for the rail
     alone). The inner's 16px margin + the row's own 8px = 24. The row runs
     the whole free width while a panel is open, so its far end keeps the
     same 24px off the window's edge, and the true-centre pair stands on the
     wall's own axis (the wall centres its tracks in that same free width).
     The !important outranks syncNavWidth's inline max-width (the wall's
     track width), which governs the beam only while no panel is open.
     ⛔ A MARGIN ON THE INNER, NEVER PADDING ON THE BAND: the band is the
     beam's query container (kamoi-beam, below), and a container query reads
     the CONTENT box, so band padding would quietly shift every shed and the
     centre's bound by 32px whenever a panel opened. */
  body.browse-sidebar-open .ink-wash-nav,
  body.settings-sidebar-open .ink-wash-nav { padding: 0; }
  body.browse-sidebar-open .nav-bar-inner,
  body.settings-sidebar-open .nav-bar-inner { margin: 0 16px; max-width: none !important; }
  /* the gap is the WALL's own side padding (24px up to 1440, 40px above,
     css/grid-mode.css .grid-container), so beam and wall breathe alike off
     the panel: 32 + the row's 8 = 40 */
  @media (min-width: 1441px) {
    body.browse-sidebar-open .nav-bar-inner,
    body.settings-sidebar-open .nav-bar-inner { margin: 0 32px; }
  }

  /* One ghost idiom: + Filter drops its chip fill and joins the tool-btn
     language (ink underline grows from center on hover). The active-filters
     indigo dot is untouched.
     ⛔ THE UNDERLINE IS ::before, THE COUNT IS ::after (desktop polish round
     3, finding 3). They shared ::after: the count (' · N', set by the
     .has-filters rule below) was painted inside the underline's absolute
     1.5px box, scaled to nothing at rest, so "+ Filter · 1" never showed and
     a stray "· 1" dropped below the button on hover. The underline carries
     no text and spans the whole label, count included. */
  .ink-wash-nav .filter-add-btn {
    background: transparent;
    padding: 0 10px;
    color: var(--text-secondary, #57534e);
    position: relative;
  }
  .ink-wash-nav .filter-add-btn:hover {
    background: transparent;
    color: var(--color-ink, #2C2C2C);
  }
  .ink-wash-nav .filter-add-btn::before {
    content: '';
    position: absolute;
    bottom: 2px;
    left: 10px;
    right: 10px;
    height: 1.5px;
    background: var(--text-secondary, #57534e);
    border-radius: 1px;
    transform: scaleX(0);
    transform-origin: center;
    transition: transform 350ms cubic-bezier(0.4, 0, 0.2, 1);
    pointer-events: none;
  }
  .ink-wash-nav .filter-add-btn:hover::before { transform: scaleX(1); }

  /* (the deck-label placard caps + the deck-btn gap left with the status
     decks, 2026-08-16 — nothing on the beam wears those classes now) */
  .ink-wash-nav .today-sep { color: rgba(44, 44, 44, 0.18); }

  /* Words, not icons: Sign in carries itself (its ghost-button dress lives
     in sync.css, shared with the hall beam). The kebab keeps its glyph (it
     IS a glyph). (The Tutor dest-button left this beam 2026-07-04.) */
  .ink-wash-nav .header-sign-in-btn svg { display: none; }

  /* Hairline harmony: structure speaks ONE ink voice (gold hairlines belong
     to the wall's seams, not to chrome). */
  .ink-wash-nav .tool-divider { background: rgba(44, 44, 44, 0.10); height: 14px; }
}

/* =============================================================================
   鴨居 KAMOI — THE LINTEL (owner-picked nav, 2026-06-11)
   One 64px beam under one hairline: identity left, today's program dead
   center (date fused into 今日 — it seeds the session and 今日の一枚),
   tools right. The legacy two rows stay in the DOM for mobile; on desktop
   buildKamoiRow() moves their members onto the beam and .kamoi hides the
   empty shells. No gold — the center earns attention through position.
   ============================================================================= */
@media (min-width: 769px) {
  .nav-bar-inner.kamoi .header-row,
  .nav-bar-inner.kamoi .tool-strip { display: none; }

  .kamoi-row {
    display: flex;
    align-items: center;
    height: 56px;   /* one panel metric with the hall beam (.gb-inner) */
    padding: 0 8px;
    gap: 14px;
    position: relative;
    z-index: 2;
  }

  .kamoi-left {
    display: flex;
    align-items: center;
    gap: 4px;
    min-width: 0;
  }

  /* The room's NAME-BOARD anchor (#roomBoardSlot, one-row beam 2026-08-16):
     an EMPTY span the two boards mount themselves into — home-hall's
     renderScopePill for a journey (道), updateRoomBoard for the two 蔵
     reference walls. It sits second in the left cluster, brand → board →
     tools, so reading order is identity → place → tools.
     THE SLOT IS A MOUNT POINT, SO IT MUST NOT PAY FOR ITSELF (corrected
     2026-08-16, same day): it shipped as `inline-flex` + `:empty{display:none}`,
     and `:empty` only answers "has no child node" — it cannot see a child that
     IS there and is display:none. That is not a corner case: a board is hidden
     while mounted whenever the wrong SPECIES is up (home-hall.css:2181-2182 —
     a WORD scope on the kanji wall, a KANJI scope on the word wall), and the
     second one happens on every cold kanji-journey entry, where enterKanjiJourney
     mounts the 道 pill and the kanji wall itself waits on the layer-2 bundle.
     In that window .kamoi-left was paying one 4px gap for an invisible slot.
     `display: contents` retires the box entirely, so BOTH cases cost nothing:
       (a) no board node   → no box, no child, no gap;
       (b) board node hidden by a species rule → no box, and the child has no
           box either, so .kamoi-left sees nothing to put a gap around;
       (c) board visible   → the pill becomes a direct .kamoi-left flex item and
           pays exactly one gap, as the slot did — .kamoi-left already carries
           the align-items:center the slot used to supply, so the board sits on
           the 56px row's optical centre unmoved (it stays baseline-aligned
           INSIDE, which is what keeps 道 / romaji / name on one line).
     It is a widening, not a change: (a) and (c) lay out identically to the
     :empty version, and the walk's `display:none !important` (study-walk.css)
     still wins over this. The dropped min-width:0 was the slot's own shrink
     licence; the board keeps its max-width and its ellipsis, so a squeezed beam
     now pushes its neighbours instead of overlapping them. */
  .kamoi-board { display: contents; }

  /* ⭐⭐ THE MODE QUESTION STANDS AT THE ROW'S TRUE CENTRE (owner 2026-08-17).
     二間 (2026-08-16) had emptied this cluster on the reading that "nothing on
     this beam is centred" — a fair design call, but it was made to escape a
     BUG, and the bug was misnamed. Centring was never the fault. Centring by
     LEFTOVER SPACE was: `margin: 0 auto` on a flex item splits what the other
     items did not take, so the room's NAME set the pair's position, and the
     pair swung 114px between rooms.
     ⛔ THE 二間 BEAM WAS WORSE ON ITS OWN MEASURE. Measured on the shipped
     one-run bar: the pair sat 113–435px left of centre and moved 219px purely
     with the room name, at 1280 / 1366 / 1440 / 1680 / 2000 alike — nearly
     double the swing that retired the centre. A run that starts after a
     variable-width name IS a drift mechanism; it just never had a pin.
     The fix is a real centre, which flex cannot express and grid can: with
     `minmax(0, 1fr) auto minmax(0, 1fr)` the two side tracks are equal BY
     CONSTRUCTION — each takes half of whatever is left — so track 2 sits on
     the row's centre line no matter what either side weighs. Re-measured:
     drift 0 at every room name × every width 1280–2000, spread 0px.
     ⛔ minmax(0, …), never a bare 1fr: `1fr` is `minmax(auto, 1fr)`, and that
     auto floor is the track's min-CONTENT width, so a long room name would
     blow the track out and overflow it instead of pressing the name to
     ellipsis. Verified both ways before this line was written. */
  .kamoi-center {
    display: flex;
    align-items: center;
    min-width: 0;
  }

  /* the left RUN: one uninterrupted reading order, gap:0 because the seams and
     the bays carry the spacing (mockup values, verbatim) */
  .kamoi-left { gap: 0; }
  .kamoi-run { display: flex; align-items: center; gap: 2px; min-width: 0; }
  /* the room's two doors keep their seats when the run is squeezed (desktop
     polish round 2, 13 October 2026, finding 3): a flex item's floor is its
     content, so the 34px glass could be pressed down to its 18px svg, and
     the room's NAME is the one thing in this run that yields */
  .kamoi-run > .lookup-glass,
  .kamoi-run > .filter-add-btn { flex: none; }
  .kamoi-seam {
    width: 1px;
    height: 16px;
    background: rgba(44, 44, 44, 0.12);
    margin: 0 14px;
    flex: 0 0 1px;
  }
  /* the room name breathes off its own tools */
  .kamoi-left .kamoi-board { margin-right: 6px; }
  .kamoi-center #queueSegment { gap: 20px; }
  /* the session phrase trails the room run. ⛔ It must NOT rejoin the pair:
     in the old centre it was an in-flow sibling that shoved Browse|Practice
     off-centre the moment the legacy 今日 session lit it, and the >=1440px
     out-of-flow hang existed only to hide that. Here it can shove nothing. */
  .kamoi-left #studyCount { margin-left: 18px; white-space: nowrap; }

  .kamoi-right {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 2px;
  }

  /* Brand — seal + wordmark + 言葉; the whole lockup is the home button */
  .kamoi-row .nav-brand {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 4px 10px 4px 0;
  }
  /* Brand lockup matches the hall beam: 34px seal + the canonical
     .kotoba-wordmark--nav logotype — the two levels read as one building. */
  .kamoi-row .brand-logo { width: 34px; height: 34px; }


  /* + Filter — same ghost voice as the other beam tools, but a stateful
     HANDLE: pressed (ink + inset underline, the settings segment idiom)
     while the panel is open; '+ Filter · N' when filters exist. */
  .kamoi-row .filter-add-btn {
    border: none;
    font-size: 12px;
    color: rgba(44, 44, 44, 0.62);
    padding: 6px 10px;
    letter-spacing: 0.2px;
  }
  .kamoi-row .filter-add-btn.panel-open,
  .kamoi-row .filter-add-btn.panel-open:focus-visible {
    color: var(--text-primary, #2C2C2C);
    box-shadow: inset 0 -2px 0 rgba(44, 44, 44, 0.55);
    /* The base pill radius curls the inset underline up the sides —
       pressed reads as ghost text over a straight ink rule. */
    background: transparent;
    border-radius: 0;
  }
  .kamoi-row .filter-add-btn.has-filters {
    color: var(--text-primary, #2C2C2C);
  }
  /* the count rides INLINE after the word at rest ("+ Filter · 1"): the same
     12px, tabular numerals, one step fainter than the ink word */
  .kamoi-row .filter-add-btn.has-filters::after {
    content: ' · ' attr(data-n);
    font-variant-numeric: tabular-nums;
    font-weight: inherit;
    color: rgba(44, 44, 44, 0.62);
  }
  /* Chip row shows in BOTH panel states (owner ruling, round 3 — hiding it
     while the panel was open read as non-interactive). */

  /* ---- The MODE pair: Browse | Practice, + #studyCount ----
     It rode a centred cluster until 二間 (2026-08-16) and now closes the left
     run, after the second seam — so this is scoped to the ELEMENT, not to a
     container it no longer sits in. ⛔ Scoping it to .kamoi-center is what
     made it vanish the first time the run was built: a container-scoped rule
     cannot follow its contents out of the container. */
  .ink-wash-nav .tool-group-queue { display: flex; align-items: center; gap: 24px; }
  /* (The Words|Kanji toggle retired 2026-07-04 — the centre holds
     Browse|Study alone; the library choice lives at level 0, the hall.) */

  /* ---- Right: [room tools] │ date · account · settings ---- */
  .kamoi-right .tool-btn {
    font-size: 12px;
    color: rgba(44, 44, 44, 0.62);
    padding: 6px 10px;
  }
  .kamoi-div {
    width: 1px;
    height: 18px;
    background: rgba(44, 44, 44, 0.12);
    margin: 0 10px;
  }
  /* The ambient date rides the right cluster ahead of the account mark —
     same order as the hall beam. */
  .kamoi-right #beamDate { margin: 0 8px 0 4px; }

  /* ⋮ ONE DOOR (desktop polish round 2, 13 October 2026, finding 3). The
     settings door wears the same seat, glyph and ink on the wall's beam as on
     the hall's: a 34px square, the ⋮ text glyph at 18px (it was a 16px svg of
     three circles here and a glyph there), faint warm ink at rest, sumi and a
     breath of ground on hover or while its rail is open. Colour and ground
     only: no lift, no shadow (the hover law). The glass beside the room's
     name takes the same 34px seat from css/vocab-palette.css. The mobile gear
     keeps the base rules above (it is .mobile-only, hidden up here). */
  .ink-wash-nav .util-btn {
    width: 34px;
    height: 34px;
    flex: none;   /* a seat, never a squeeze: a tight row sheds, the door holds */
    padding: 0;
    border: none;
    border-radius: 8px;
    background: transparent;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-ui, 'Inter', system-ui, sans-serif);
    font-size: 18px;
    line-height: 1;
    color: var(--color-faint-warm, #6E6860);
    transition: color .2s ease, background-color .2s ease;
  }
  .ink-wash-nav .util-btn:hover,
  .ink-wash-nav .util-btn[aria-expanded="true"] {
    color: var(--color-ink, #2C2C2C);
    background: rgba(44, 44, 44, 0.05);
  }
  /* the one keyboard ring (the shared ACCESSIBILITY rule draws the same ring
     through the --accent alias; this names the token the hall's door uses) */
  .ink-wash-nav .util-btn:focus-visible {
    outline: 2px solid var(--color-accent, #3D5A80);
    outline-offset: 2px;
  }
  /* the account and the door stand apart as they do on the hall's beam
     (.gb-right, 12px): the 2px that sat between the old 32px seats read as
     one cramped pair beside a bordered Sign in */
  .kamoi-right .nav-utils { gap: 12px; }

  /* (#reviewSubtabs' under-beam padding retired 2026-08-16 — that node has
     had no emitter since the review/refresh split went 2026-07-14, and the
     under-beam line it padded is gone.) */
}

/* ════════════════════════════════════════════════════════════════════
   Browse / Study path tabs (beam centre) + the under-beam LINE.
   The two-path model made visible (owner 2026-06-15). Desktop beam only —
   #queueSegment is hide-mobile (display:none !important on ≤768px), so
   these non-important rules never leak onto mobile. (#browseSubrow, the
   other hide-mobile half of that pair, is gone — see below.)
   ════════════════════════════════════════════════════════════════════ */
.ink-wash-nav .tool-group-queue[role="tablist"] { display: flex; align-items: center; gap: 24px; }
.ink-wash-nav .path-tab {
  display: inline-flex;
  align-items: center;
  border: none;
  background: transparent;
  box-shadow: none;
  cursor: pointer;
  font-family: 'Inter', sans-serif;
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0.03em;
  color: rgba(44, 44, 44, 0.46);
  padding: 0 2px;
  position: relative;
  transition: color 0.25s ease;
}
.ink-wash-nav .path-tab:hover { color: rgba(44, 44, 44, 0.82); }
.ink-wash-nav .path-tab.active { color: var(--color-ink, #2C2C2C); }
/* thin sumi underline on the active path */
.ink-wash-nav .path-tab.active::after {
  content: '';
  position: absolute;
  left: 2px; right: 2px; bottom: -6px;
  height: 1.5px;
  background: var(--color-ink, #2C2C2C);
  border-radius: 1px;
}
/* ONE RING (desktop polish round 3, finding 10): the tabs showed focus by
   colour alone, and the ACTIVE tab is already ink, so focusing it showed
   nothing at all. The one ring, 2px off the word; the colour lift stays. */
.ink-wash-nav .path-tab:focus-visible {
  outline: 2px solid var(--color-accent, #3D5A80);
  outline-offset: 2px;
  box-shadow: none;
  border-radius: 2px;
  color: var(--color-ink, #2C2C2C);
}

/* ── THE ROW IS GONE, THE LINE REMAINS (owner 2026-08-16) ─────────────────
   .browse-subrow was the geometry of row 2: one centred line directly under
   the beam. Its BROWSE occupants — the four status decks, the room's
   name-board — have left (the decks retired outright, the board moved up
   into .kamoi-left). The class survives with exactly ONE consumer: the 稽古
   walk's session lintel, which study-walk.js dresses as "kw-lintel
   browse-subrow" (its mount, `_lintelEl.className` — cited by symbol because a
   comment-only edit moves a line number) so the walk's under-beam line has
   ONE definition and can never become a pixel-twin of a row it copied.
   ⛔ Deleting this rule UNDRESSES the walk lintel — it has no other box
   geometry anywhere (css/study-walk.css styles only its .kw-lintel-* parts).
   .kw-lintel is named alongside so the geometry survives the day the legacy
   class name is dropped from study-walk.js; the two always co-occur today,
   so this is a widening, never a change. */
/* ⛔ .browse-subrow LEFT THIS SELECTOR 2026-08-16 and is now dead everywhere:
   the walk's lintel was its last wearer and it rides .kamoi-right on the beam
   instead (study-walk.js `_lintelEl.className`), so nothing emits the class.
   The note above is half-history — keep it for the WHY, not as a warning.
   What survives here is the lintel's fallback box: on the beam the tighter
   .kw-lintel--beam rule (css/study-walk.css) wins, and this is what dresses
   the pre-kamoi / headless mounts that still land in #navExpandZone. */
.ink-wash-nav .kw-lintel { display: flex; justify-content: center; align-items: center; gap: 18px; padding: 2px 8px 9px; }
/* (.browse-subtabs — the decks' own flex track — retired with them.) */
.ink-wash-nav .study-count[hidden] { display: none; }

/* The walk lintel's one NUMBER. (It shared this rule with the decks'
   .deck-num, so the bar read as one system; the decks are gone, the stamp
   is unchanged so the walk's line still matches the beam above it.) */
.ink-wash-nav .kw-lintel .n { font-size: 13px; font-weight: 600; color: var(--color-ink, #2C2C2C); font-variant-numeric: tabular-nums; }

/* Session count — the legacy 今日 deck's quiet phrase. It rides the beam
   CENTRE now, beside the Browse|Practice tabs (buildKamoiRow), and is
   hidden unless that session is live; the ink is unchanged. */
.ink-wash-nav .study-count { font-family: 'Inter', sans-serif; font-size: 11.5px; letter-spacing: 0.04em; color: rgba(44, 44, 44, 0.6); }

/* Kanji coverage meter — the second quiet phrase on the study line: what the
   mastered kanji buy ("Your 12 kanji cover 18% of everyday text"). Fainter
   than the day count; hides while the session-end card carries the line.
   ⚠️ NO EMITTER — nothing in js/ or index.html writes .study-coverage, and
   nothing did before 2026-08-16 either (pre-existing, not a casualty of the
   one-row beam). Left standing like .today-prefix* above: retiring it is its
   own audit, not this one's. */
.ink-wash-nav .study-coverage { font-family: 'Inter', sans-serif; font-size: 11.5px; letter-spacing: 0.04em; color: rgba(44, 44, 44, 0.42); }
.ink-wash-nav .study-coverage[hidden] { display: none; }

/* Beam date (right cluster, ahead of the account mark — one right-cluster
   order with the hall beam): 今日 + the date. Chrome speaks twice, not three
   times (owner verbosity ruling 2026-07-04) — the romaji gloss retired. */
.ink-wash-nav .beam-date { display: inline-flex; align-items: center; gap: 7px; }
.ink-wash-nav .dayline-jp { font-family: 'Klee One', 'Noto Sans JP', sans-serif; font-size: 13.5px; color: var(--color-ink, #2C2C2C); }

/* Shared beam "stamp": the small uppercase labels — the date suffix and the
   walk lintel's labels — one treatment so the whole bar speaks one language
   in both modes. (The status decks' .deck-label was the third member until
   2026-08-16; the stamp itself is unchanged, so the walk's line still reads
   as a sibling of the date above it.) */
.ink-wash-nav .dayline-date,
.ink-wash-nav .kw-lintel .lbl {
  font-family: 'Inter', sans-serif;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--text-tertiary, #8C8578);
}

/* ⛔ THE CENTRING AND ITS GUARDS ARE RETIRED (二間, 2026-08-16). A rule here
   used to drop the absolute centring below 1440px and let the pair flow on
   `margin: 0 auto`, which is not centring: with .kamoi-right also carrying
   margin-left:auto the free space split around whatever the LEFT cluster
   weighed, so the ROOM'S NAME moved the mode pair — measured at 1280px,
   蔵 Every word 44px left · 道 Food 86px left · 道 Food, drink and the kitchen
   table 28px RIGHT, a 114px swing. It was pinned at every width for a few
   hours; then the owner picked B, which deletes the mechanism instead of
   guarding it. Nothing is positioned against the viewport now, so there is
   nothing left to pin, cap or drift. The <=1199px wrap below stays: that is
   the beam gracefully becoming two lines, which is a different question. */
/* ── THE BEAM READS ITS OWN WIDTH (desktop polish round 3, 13 October 2026,
   finding 6) ───────────────────────────────────────────────────────────────
   Round 2's centre and sheds keyed on the WINDOW. A side panel takes 200 to
   260px of it, so at 1280 with the filter panel or the rail open the row was
   1024 wide, no shed fired (the window was still 1280), the true-centre grid
   held, and the room's name was cut to "Every wo…" by a fraction of a pixel
   while the right half stood 100px empty. The beam is its own query container
   now (.ink-wash-nav, `kamoi-beam`), and every rule below asks how wide the
   BEAM is. With no panel open the beam is the window, so the numbers are
   round 2's and nothing changes there (1680 included); with a panel open the
   same numbers apply to the beam that is left.

   ── THE TRUE CENTRE (owner 2026-08-17) ──────────────────────────────────────
   A grid with `minmax(0, 1fr) auto minmax(0, 1fr)` is a real centre: the two
   side tracks are equal BY CONSTRUCTION, so the pair stands on the row's
   centre line whatever either side weighs. What bounds it is FIT: the left
   cluster must fit in half of what the pair leaves. A bare window's beam
   holds that from 1100px (round 2: half the pair's leftover is 410px there,
   and "蔵 kura Every word" needs 373px). A side panel's beam runs its whole
   free width at 24px a side (the band block above), 64px wider than a bare
   window's track-aligned row at the same beam width, so it holds the centre
   from 1010px: half is then 397px, room for the board and a two-digit
   "+ Filter · 12" (397px). 1280 with a 256px panel or rail is a 1024px beam:
   the centre holds and the name reads whole. Below the bound the pair
   follows the room's tools in a plain flex row and never overlaps them.
   ⛔ NO justify-self ON THE SIDES. They must STRETCH to fill their tracks: an
   item sized to its own content (justify-self:start) is measured at
   max-content and simply OVERFLOWS a track too small for it — the room name
   then reaches under the pair instead of yielding. Stretched, the track's
   width is a real constraint, and the shrink chain below decides who gives. */
@media (min-width: 769px) {
  .ink-wash-nav { container: kamoi-beam / inline-size; }

  /* WHO YIELDS WHEN THE ROW IS TIGHT, in order: the sheds below, then the
     room NAME, and only the room name. Each link needs its own min-width:0 or
     the shrink stops there (a flex item's default min-width is auto =
     min-content, and the pill is white-space:nowrap, so without these the
     chain is rigid and the left run overflows instead). .jsp-name carries
     the ellipsis. Nothing else may shrink: a door keeps its seat, the mode
     pair and the right cluster keep their size. */
  .kamoi-center,
  .kamoi-right { flex-shrink: 0; }
  .kamoi-row .nav-brand { flex: none; }
  .kamoi-left .kamoi-run { min-width: 0; }
  .kamoi-left .journey-scope-pill { min-width: 0; flex: 0 1 auto; }
  .kamoi-left .journey-scope-pill .jsp-name { min-width: 0; }
}
@container kamoi-beam (width >= 1100px) {
  .kamoi-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  }
  .kamoi-left { justify-content: flex-start; }
  .kamoi-center { justify-self: center; }
  /* margin-left:auto was the flex row's "push me right"; a grid track already
     ends where the row ends, and leaving it in makes the cluster start at its
     own right edge. */
  .kamoi-right { justify-content: flex-end; margin-left: 0; }
}
@container kamoi-beam (1010px <= width < 1100px) {
  body:is(.browse-sidebar-open, .settings-sidebar-open) .kamoi-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  }
  body:is(.browse-sidebar-open, .settings-sidebar-open) .kamoi-left { justify-content: flex-start; }
  body:is(.browse-sidebar-open, .settings-sidebar-open) .kamoi-center { justify-self: center; }
  body:is(.browse-sidebar-open, .settings-sidebar-open) .kamoi-right { justify-content: flex-end; margin-left: 0; }
}

/* ── ONE ROW: THE BEAM SHEDS, IT DOES NOT WRAP ─────────────────────────────
   (round 2, finding 11; keyed on the beam's own width since round 3.) The
   beam stays one 56px line and gives things up in a fixed order as it
   narrows, the room's name last of all:
     1. the ambient date (今日 + the day) leaves first, below 1100px: it is
        the one piece on the beam nobody acts on;
     2. the reference board's romaji ("kura") leaves below 1000px; its kanji
        and the room's name stay;
     3. the Hide button keeps its icon and its title and drops its word,
        below 900px.
   Only then does the name ellipse (the shrink chain above). */
/* shed 1: the date */
@container kamoi-beam (width < 1100px) {
  .kamoi-right #beamDate { display: none; }
}
/* shed 2: the board's romaji */
@container kamoi-beam (width < 1000px) {
  .kamoi-row .journey-scope-pill .jsp-romaji { display: none; }
}
/* shed 3: the Hide button's word. Its label is a bare text node that
   syncHideToggleState (grid-mode.js) rewrites in place, so the word goes by
   type size, not by a selector; the icon is a fixed 13px svg and stays, the
   title ("Hide one language (H)") still names it, and the gap that stood
   between the icon and the word closes with it. */
@container kamoi-beam (width < 900px) {
  .kamoi-right #hideToggleBtn { font-size: 0; gap: 0; }
}
/* The last resort, a side panel's beam only (a bare window's beam is at
   least 769px and holds one line there, round 2, its name cut to "Every…"
   at worst). Measured with the filter panel open: one line holds the name
   whole down to a 730px beam, cuts it to "Every…" (43px) at 700px, to a
   stub of two letters at 670px, and cannot hold at all under 630px. So
   under 700px the row wraps, as it always did here, and keeps the name
   whole, rather than print a name nobody can read or paint the mode pair
   over + Filter. Flex wraps BEFORE it shrinks, so this must not open any
   wider than that. */
@container kamoi-beam (width < 700px) {
  body:is(.browse-sidebar-open, .settings-sidebar-open) .kamoi-row {
    flex-wrap: wrap;
    height: auto;
    min-height: 56px;
    row-gap: 4px;
  }
}
