/* The fleet shell (2026-10-05): YOKU ONE's sidebar, brand band + wave, nav, icon rail, phone menu and
   white top bar, ported from yoku-one static/yoku-one.css + admin.css (origin/master 3e50d51) so this
   app looks like the rest of the fleet (YOKU ONE, YOKU CS). Markup: templates/base.html. Class names are
   the fleet's own (.app-sidebar, .app-brand, .app-nav, .app-nav-item, .app-topbar, .page-app …) — never
   rename them, so a change there ports as a copy.
   Translation: YOKU ONE's rules read the fleet token NAMES (--card, --muted, --primary-light, --brand-deep,
   radius-sm = 12px …); here they read this app's tokens.css (generated from the design system's
   tokens.json) for the same values: --surface, --ink-muted, --brand-100, --brand-600, --radius-md … */

/* ── App shell: sidebar + topbar + content ─────────────────────────────────── */
.page.page-app {
  --sidebar-w: 244px;
  --topbar-action-size: 2.35rem;
  max-width: none;
  width: 100%;
  margin: 0;
  display: grid;
  grid-template-columns: var(--sidebar-w) minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr);
  grid-template-areas: "side top" "side main";
  min-height: 100vh;
}

/* ── Sidebar ────────────────────────────────────────────────────────────────── */
.app-sidebar {
  grid-area: side;
  position: sticky;
  top: 0;
  align-self: start;
  height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-right: 1px solid var(--border);
  z-index: 6;
}

.app-brand {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.65rem;
  padding: 1.1rem 1.05rem 2rem;
  --wave-fill: var(--surface);
  --wave-height: 36px;
  background:
    radial-gradient(115% 130% at 100% 0%, color-mix(in srgb, var(--on-brand) 42%, transparent) 0%, transparent 60%),
    var(--brand-600);
  color: var(--on-brand);
  text-decoration: none;
}
.app-brand:hover { color: var(--on-brand); }
/* The Yoku Group logo on its white plate (as YOKU CS). */
.shell-logo { flex: 0 0 auto; width: 36px; height: 36px; border-radius: var(--radius-md); background: #fff;
  padding: 3px; object-fit: contain; }

/* ── Wave divider (fleet component) — byte-identical to the yoku-one / claim / stock / equipment-loan
   copies; change the shape in one app only by changing it in all of them. ── */
:root {
  --wave-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 120' preserveAspectRatio='none'%3E%3Cpath fill='%23000' fill-opacity='.18' d='M0 18c240 74 470 60 720 8s470-30 720 44V120H0Z'/%3E%3Cpath fill='%23000' fill-opacity='.3' d='M0 48c220-34 450 60 700 46s520-70 740 6V120H0Z'/%3E%3Cpath fill='%23000' d='M0 66c230 54 450-40 700-20s540 66 740 28V120H0Z'/%3E%3C/svg%3E")
    no-repeat center / 100% 100%;
}

.wave-divider,
.page-header::after,
.app-brand::after,
.app-band::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  pointer-events: none;
  height: var(--wave-height, 52px);
  background: var(--wave-fill, var(--surface));
  -webkit-mask: var(--wave-mask);
  mask: var(--wave-mask);
}

/* ── Brand lockup ── */
.yo-wordmark { display: inline-flex; align-items: baseline; gap: 0.32em; font-size: 1.02rem; font-weight: 800;
  letter-spacing: 0.08em; line-height: 1.1; white-space: nowrap; }
.yo-word-yoku { color: var(--on-brand); }
.yo-word-one { color: var(--aqua-400); }   /* the design system README: the wordmark's second half in aqua-400 (bold, large: 3:1 floor) */
.yo-word-th { letter-spacing: 0; }   /* a Thai word: no tracking (the Thai Room Rule) */
/* Thai: no letter-spacing (the Thai Room Rule). */
.yo-brand-tag { display: block; font-size: 0.72rem; font-weight: 600; margin-top: 0.1rem;
  color: color-mix(in srgb, var(--on-brand) 78%, transparent); }

/* ── Nav ── */
.app-nav {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.85rem 0.65rem 0.75rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  /* The Hidden Scrollbar Rule (YOKU ONE DESIGN.md, 2026-10-05; here 2026-10-09): it scrolls, it never shows
     a scrollbar or scrolls sideways. In the icon rail a scrollbar pushed every icon off the rail's centre. */
  overflow-x: hidden;
  scrollbar-width: none;
}

.app-nav::-webkit-scrollbar {
  display: none;
}

.app-nav-item {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.62rem 0.7rem;
  border-radius: var(--radius-md);
  color: var(--ink);
  text-decoration: none;
  font-size: 0.9rem;
  font-weight: 400;
  line-height: 1.35;
  transition: background-color 120ms ease, color 120ms ease;
}
.app-nav-item:hover { background: var(--surface-sunken); color: var(--ink); }
.app-nav-icon { display: inline-flex; color: var(--ink-muted); flex: 0 0 auto; }
.app-nav-item.is-active { background: var(--brand-100); color: var(--brand-text); font-weight: 600; }
.app-nav-item.is-active .app-nav-icon { color: var(--brand-text); }
.app-nav-label { min-width: 0; }
.app-nav-divider { border: 0; border-top: 1px solid var(--border); margin: 0.6rem 0.7rem; }

/* Group headings fold (<details>); Thai labels: no uppercase, no tracking. */
.app-nav-group { font-size: 0.75rem; font-weight: 600; color: var(--ink-muted); }
.app-nav-fold-head {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0.55rem 0 0.1rem;
  padding: 0.35rem 0.7rem;
  border-radius: var(--radius-md);
  cursor: pointer;
  list-style: none;
  transition: color 120ms ease, background-color 120ms ease;
}
.app-nav-fold:first-child > .app-nav-fold-head { margin-top: 0; }
.app-nav-fold-head::-webkit-details-marker { display: none; }
.app-nav-fold-head:hover { color: var(--ink); background: var(--surface-sunken); }
.app-nav-fold-head:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }
.app-nav-chevron { display: inline-flex; margin-left: auto; }
.app-nav-fold[open] .app-nav-chevron { transform: rotate(90deg); }
.app-nav-fold-items > .app-nav-item + .app-nav-item { margin-top: 0.15rem; }
@media (min-width: 981px) and (prefers-reduced-motion: no-preference) {
  .app-nav-ready .app-nav-fold { interpolate-size: allow-keywords; }
  .app-nav-ready .app-nav-fold::details-content { block-size: 0; opacity: 0; overflow-x: visible; overflow-y: clip;
    transition: block-size 220ms ease, opacity 220ms ease, content-visibility 220ms allow-discrete; }
  .app-nav-ready .app-nav-fold[open]::details-content { block-size: auto; opacity: 1; }
  .app-nav-ready .app-nav-chevron { transition: transform 220ms ease; }
}

/* A count pill (รอมอบหมาย / ปฏิทินส่งของ). */
.app-nav-item .nav-badge {
  margin-left: auto;
  flex: 0 0 auto;
  min-width: 1.5rem;
  padding: 0.05rem 0.45rem;
  border-radius: var(--radius-pill);
  background: var(--brand-600);
  color: var(--on-brand);
  font-size: 0.7rem;
  font-weight: 700;
  line-height: 1.5;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.app-nav-item.is-active .nav-badge { background: var(--brand-700); }
/* the Approval link's badge holder (approval-act.js redraws it after a press): no box of its own */
.app-nav-item .sb-await { display: contents; }
@supports (text-box: trim-both cap alphabetic) {
  .app-nav-item .nav-badge { display: inline-block; line-height: 1; text-box: trim-both cap alphabetic; padding: 0.33rem 0.45rem; }
}

/* ── Top bar ── */
.app-topbar {
  grid-area: top;
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  padding: 0.95rem 1.6rem;
  background: color-mix(in srgb, var(--surface) 94%, transparent);   /* white, as YOKU CS */
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--border);
}
/* The title side takes the room and the controls never wrap under it: a long page_sub used to push the
   bell / user / sign-out onto a second row and grow the sticky bar to ~160px (critique 2026-10-16). */
.app-topbar-head { flex: 1 1 0; min-width: 0; }
.app-page-title { font-size: 1.26rem; font-weight: 600; line-height: 1.3; color: var(--ink); }
.app-page-sub { font-size: 0.85rem; color: var(--ink-muted); margin-top: 0.12rem;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; }
.app-page-sub:empty { display: none; }
.app-topbar-actions { flex: none; display: flex; align-items: center; gap: clamp(0.3rem, 1.5vw, 0.55rem); }

.app-icon-btn,
.app-topbar .bell {
  width: var(--topbar-action-size);
  height: var(--topbar-action-size);
  flex: 0 0 auto;
  border-radius: var(--radius-md);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--ink-muted);
  text-decoration: none;
  position: relative;
  margin: 0;
  transition: background-color 120ms ease, border-color 120ms ease, color 120ms ease;
}
.app-icon-btn:hover,
.app-topbar .bell:hover { color: var(--brand-text); border-color: var(--brand-600); background: var(--brand-100); }
/* The unread count: Alarm Red, cut into its button by a ring of the card colour. */
.app-topbar .bell.has-unread .bell-count {
  position: absolute; top: -6px; right: -6px; min-width: 18px; height: 18px; padding: 0 5px;
  border-radius: var(--radius-pill); background: var(--danger-solid); color: var(--on-danger);
  box-shadow: 0 0 0 2px var(--surface); font-size: 0.66rem; font-weight: 700; line-height: 18px; text-align: center;
  font-variant-numeric: tabular-nums;
}

/* Who is signed in (YOKU ONE admin.css). */
.ac-admin-chip {
  display: flex; align-items: center; gap: 0.55rem; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius-md); padding: 0.28rem 0.9rem 0.28rem 0.3rem;
}
.ac-avatar {
  width: 32px; height: 32px; border-radius: 50%; background: var(--brand-100); color: var(--brand-text);
  display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
}
.ac-admin-name { display: block; font-size: 0.85rem; font-weight: 700; line-height: 1.25; color: var(--ink);
  max-width: clamp(80px, 28vw, 168px); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ac-admin-role { display: block; font-size: 0.72rem; color: var(--ink-muted); line-height: 1.25; }

/* ── Light / dark switch (YOKU ONE): moon in light mode, sun in dark. ── */
button.app-icon-btn { padding: 0; font: inherit; cursor: pointer; }
.theme-icon-moon, .theme-icon-sun { display: inline-flex; }
[data-theme="dark"] .theme-icon-moon, :root:not([data-theme="dark"]) .theme-icon-sun { display: none; }
.app-band-bell, .app-menu-foot { display: none; }

/* ── Content column ── */
.page-app > .page-content { grid-area: main; min-width: 0; padding: 1.4rem 1.6rem 3rem; width: 100%; }
/* Room under the last row for the floating ถามบอท button (style.css's .page-content.has-bot, which the
   rule above would otherwise override; scripts/bell_check.py checks it sits clear of the last entry). */
.page-app > .page-content.has-bot { padding-bottom: 84px; }

.app-burger, .app-rail-row { display: none; }

/* ── Desktop: the sidebar collapses to an icon rail (YOKU ONE 2026-10-01) ──
   html.nav-collapsed = the width (76px), html.nav-compact = the content (labels screen-reader-only, band
   text hidden, badges on the icon's corner, group headings a thin divider). shell.js moves them. */
@media (min-width: 981px) {
  .app-rail-row { display: flex; justify-content: flex-end; padding: 0.5rem 0.65rem 0; }
  .app-rail-row + .app-nav { padding-top: 0.35rem; }
  html.nav-collapsed .app-rail-toggle { transform: translateX(calc(0.65rem - 21px)); }
  .app-rail-toggle {
    display: inline-grid; place-items: center; width: 34px; height: 34px; padding: 0; border: 0;
    border-radius: var(--radius-md); background: transparent; color: var(--ink-muted); cursor: pointer;
    transition: color 120ms ease, background-color 120ms ease;
  }
  .app-rail-toggle:hover { background: var(--surface-sunken); color: var(--ink); }
  .app-rail-collapse, .app-rail-expand { display: inline-flex; }
  .app-rail-expand, html.nav-collapsed .app-rail-collapse { display: none; }
  html.nav-collapsed .app-rail-expand { display: inline-flex; }
  html.nav-collapsed .page.page-app { --sidebar-w: 76px; }
  .app-nav-item { position: relative; padding-left: 0.85rem; min-height: calc(0.9rem * 1.35 + 1.24rem); }
  html.nav-compact .app-brand > span { display: none; }
  html.nav-compact .app-brand { min-height: var(--brand-h, auto); padding-left: 0; padding-right: 0; justify-content: center; }
  html.nav-compact .app-nav-label,
  html.nav-compact .app-nav-fold-label {
    position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
  }
  html.nav-compact .app-nav-item .nav-badge { position: absolute; top: 2px; left: 27px; min-width: 1.15rem; margin: 0;
    padding: 0 0.3rem; font-size: 0.62rem; }
  @supports (text-box: trim-both cap alphabetic) { html.nav-compact .app-nav-item .nav-badge { padding: 0.27rem 0.3rem; } }
  html.nav-compact .app-nav-fold-head { justify-content: center; margin: 0.45rem 0 0.1rem; padding: 0.4rem 0;
    border-top: 1px solid var(--border); border-radius: 0; }
  html.nav-compact .app-nav-chevron { margin-left: 0; }
  html.nav-compact .app-nav-divider { margin-left: 0; margin-right: 0; }
}
@media (min-width: 981px) and (prefers-reduced-motion: no-preference) {
  html:has(.app-nav-ready) .page.page-app { transition: grid-template-columns 200ms ease; }
  html:has(.app-nav-ready) .app-rail-toggle { transition: color 120ms ease, background-color 120ms ease, transform 200ms ease; }
  html.nav-reveal .app-nav-label, html.nav-reveal .app-nav-fold-label, html.nav-reveal .app-nav-item .nav-badge,
  html.nav-reveal .app-nav-chevron, html.nav-reveal .app-brand > span { animation: nav-reveal 160ms ease both; }
  @keyframes nav-reveal { from { opacity: 0; } }
}

/* ── Phone (≤980px): the band on top, the menu folded under a burger; open, the sidebar becomes a
   full-screen menu over the page (YOKU ONE 2026-10-01 — no drawer, no backdrop). ── */
@media (max-width: 980px) {
  .page.page-app { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto auto minmax(0, 1fr);
    grid-template-areas: "side" "top" "main"; }
  .app-sidebar { position: relative; height: auto; border-right: none; border-bottom: 1px solid var(--border); }
  .app-brand { padding: 0.85rem 1rem 1.4rem; }
  .app-nav { display: none; padding: 0.5rem 0.75rem 0.85rem; }
  html.nav-open .app-nav { display: flex; padding: 0.75rem 1rem 2.5rem; gap: 0.25rem; }
  .app-nav-item { padding: 0.7rem 0.75rem; }
  html.nav-open .app-sidebar { position: fixed; inset: 0; z-index: 60; height: 100dvh; overflow-y: auto;
    overscroll-behavior: contain; border-bottom: 0; }
  html.nav-open, html.nav-open body { overflow: hidden; }
  html { scrollbar-gutter: stable; }
  html.nav-open .app-topbar { margin-top: var(--closed-side-h, 0px); }
  html.nav-open .app-nav-item { padding: 0.85rem 0.9rem; font-size: 1rem; }
  .app-burger {
    display: inline-flex; align-items: center; justify-content: center; position: absolute; top: 0.85rem; right: 1rem;
    z-index: 2; width: 44px; height: 44px; padding: 0; border-radius: var(--radius-md); color: var(--on-brand);
    background: color-mix(in srgb, var(--on-brand) 14%, transparent);
    border: 1px solid color-mix(in srgb, var(--on-brand) 22%, transparent); cursor: pointer;
  }
  .app-burger:hover { background: color-mix(in srgb, var(--on-brand) 24%, transparent); }
  .app-burger:focus-visible { outline-color: var(--on-brand); }
  .app-burger-open, .app-burger-close { display: inline-flex; line-height: 0; }
  .app-burger-close, html.nav-open .app-burger-open { display: none; }
  html.nav-open .app-burger-close { display: inline-flex; }
  .app-topbar { position: static; padding: 0.9rem 1rem; }
  /* One place for each control (One Platform, 2026-10-07): the band holds the bell and the burger, the
     row under it is just the page title, and who / dark mode / sign out are the open menu's foot. */
  .app-topbar-actions { display: none; }
  .app-band-bell {
    display: inline-flex; align-items: center; justify-content: center; position: absolute; top: 0.85rem;
    right: calc(1rem + 44px + 0.5rem); z-index: 2; width: 44px; height: 44px; margin: 0; border-radius: var(--radius-md);
    color: var(--on-brand); background: color-mix(in srgb, var(--on-brand) 14%, transparent);
    border: 1px solid color-mix(in srgb, var(--on-brand) 22%, transparent);
  }
  .app-band-bell:hover { background: color-mix(in srgb, var(--on-brand) 24%, transparent); }
  .app-band-bell:focus-visible { outline-color: var(--on-brand); }
  html.nav-open .app-nav { padding-bottom: 1rem; }
  html.nav-open .app-menu-foot {
    display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem; margin: 0 1rem; padding: 1rem 0 2.5rem;
    border-top: 1px solid var(--border);
  }
  .app-menu-foot .btn { flex: 1 1 10rem; justify-content: center; gap: 0.45rem; min-height: var(--size-tap); }
  .app-menu-who { flex: 1 1 100%; display: flex; align-items: center; gap: 0.6rem; }
  .app-menu-who > span:last-child { display: flex; flex-direction: column; min-width: 0; }
  .app-menu-who .ac-admin-name { max-width: none; }
  .page-app > .page-content { padding: 1.1rem 1rem 2.5rem; }
}
@media (max-width: 980px) and (prefers-reduced-motion: no-preference) {
  html.nav-open .app-nav { animation: nav-list-in 160ms ease both; }
  @keyframes nav-list-in { from { opacity: 0; transform: translateY(-6px); } }
}
@media (max-width: 560px) {
  .app-page-title { font-size: 1.12rem; }
}

/* ── Signed out (login): the plain page under the brand band + wave ── */
.page:not(.page-app) > .page-header {
  position: relative;
  padding-bottom: 2.2rem;
  --wave-fill: var(--surface-page);
  --wave-height: 52px;
  background:
    radial-gradient(115% 130% at 100% 0%, color-mix(in srgb, var(--on-brand) 42%, transparent) 0%, transparent 60%),
    var(--brand-600);
  color: var(--on-brand);
}

@media (prefers-reduced-motion: reduce) {
  .app-nav-chevron, .app-nav-fold-head, .page.page-app, .app-rail-toggle { transition: none !important; }
}

/* ── Moving between pages (One Platform README, "Moving between pages") ──
   The bar: brand-600 over a 16% brand-600 track, one pass every 1.05s (shell.js shows it on a click).
   The arrival: a cross-document view transition fades the content column up 10px; only the content is
   named, so the sidebar and top bar hold still. Under reduced motion: no arrival, and a still bar. */
.op-nav-progress { position: fixed; top: 0; left: 0; right: 0; z-index: 100; height: 3px; overflow: hidden;
  pointer-events: none; background: color-mix(in srgb, var(--brand-600) 16%, transparent); }
.op-nav-progress[hidden] { display: none; }
.op-nav-progress__bar { width: 40%; height: 100%; background: var(--brand-600); animation: op-nav-slide 1.05s ease-in-out infinite; }
@keyframes op-nav-slide { from { transform: translateX(-100%); } to { transform: translateX(250%); } }
.op-nav-pending { opacity: 0.55; }
@media (prefers-reduced-motion: reduce) { .op-nav-progress__bar { width: 100%; animation: none; } }
/* The opt-in itself (@view-transition { navigation: auto }) is added by base.html's head script, so only a page
   running JavaScript animates: with scripting off, the second page change in a row stayed covered by the
   transition and taps never reached the page (scripts/bell_check.py, no-JS pass, in Chrome too). */
@media (prefers-reduced-motion: no-preference) {
  .page-app > .page-content { view-transition-name: page-content; }
  ::view-transition-old(root), ::view-transition-new(root) { animation-duration: 0.18s; }
  ::view-transition-old(page-content) { animation: op-page-out 0.14s ease-in both; }
  ::view-transition-new(page-content) { animation: op-page-in 0.3s cubic-bezier(0.2, 0.7, 0.2, 1) both; }
}
@keyframes op-page-out { to { opacity: 0; } }
@keyframes op-page-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

/* ── The menu's search (2026-10-06, as YOKU CS): in the row with |< on a desk, at the top of the open
   menu on a phone; gone in the icon rail, which has no room for words. shell.js filters. ── */
.app-nav-search { position: relative; display: flex; flex: 1; min-width: 0; align-items: center; }
.app-nav-search .ic { position: absolute; left: 0.6rem; color: var(--ink-muted); pointer-events: none; }
.app-nav-search input { width: 100%; min-width: 0; padding: 0.45rem 0.6rem 0.45rem 2rem; font: inherit; font-size: 0.88rem;
  border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface); color: var(--ink); }
.app-nav-search input:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -1px; }
.app-nav-empty { margin: 0.6rem 0.85rem; font-size: 0.85rem; color: var(--ink-muted); }
@media (min-width: 981px) {
  .app-rail-row { justify-content: space-between; align-items: center; gap: 0.4rem; }
  html.nav-compact .app-nav-search { display: none; }
  html.nav-collapsed .app-rail-row { justify-content: flex-end; }
}
@media (max-width: 980px) {
  html.nav-open .app-rail-row { display: flex; padding: 0.75rem 1rem 0; }
  .app-rail-toggle { display: none; }
  .app-nav-search input { font-size: 1rem; padding-top: 0.6rem; padding-bottom: 0.6rem; }
}
/* the search hides with [hidden]; a menu item's own display: flex would otherwise keep it on screen */
.app-nav-item[hidden], .app-nav-fold[hidden], .app-nav-divider[hidden] { display: none; }

/* Skip link (critique 2026-10-16): the first Tab stop on every signed-in page, hidden until focused, so a
   keyboard user is not walked through ~25 sidebar controls before the page itself. */
.skip-link {
  position: fixed; top: 0.5rem; left: 0.5rem; z-index: 100; padding: 0.6rem 1rem; border-radius: var(--radius-md);
  background: var(--brand-600); color: var(--on-brand); font-weight: 600; text-decoration: none;
  transform: translateY(-200%);
}
.skip-link:focus-visible { transform: none; }
#main-content:focus { outline: none; }
