/* base.css — the application frame: the navigation column, the toolbar above
 * the page, and the page itself. What sits inside a page is components.css,
 * and anything naming a colour or a measure is a token in theme.css.
 *
 * The frame is drawn by nav.js on every page, so a page's own markup is its
 * heading and its content and nothing else.
 *
 *
 * LOGICAL PROPERTIES, NOT LEFT AND RIGHT
 *
 * `margin-inline-start`, `inset-inline-end`, `text-align: start`. Nothing in
 * this build is right-to-left yet, and the reason to write it this way now is
 * that what makes RTL expensive later is a thousand `margin-left`s rather
 * than a translation (SW-01; docs/ngon-ngu/README.md §5). `dir` is set on
 * <html> from the locale table, so adding a right-to-left language is a row
 * in src/core/locale.c and a catalogue file.
 *
 * The one physical thing left is `transform: translateX()` on the narrow
 * screen's drawer, which has no logical form -- so it is flipped explicitly
 * under [dir="rtl"].
 */

* { box-sizing: border-box; }

/* The `hidden` attribute has to win: a browser hides it with a rule any author
   rule beats, and every flex container in this console carries it at some
   point. */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--desk);
  color: var(--ink);
  font: 14px/1.5 var(--sans);
}

a { color: var(--brand); }
a:hover { color: var(--brand-bright); }

h1, h2, h3 { margin: 0; font-weight: 700; letter-spacing: -.01em; }

code, kbd, samp { font-family: var(--mono); font-size: .92em; }

/* ── The frame ──────────────────────────────────────────────────────
 *
 * A fixed column on the left, everything else in a scrolling column on the
 * right. Fixed rather than scrolling with the page because every working
 * screen here is a long table, and navigation that scrolls away is navigation
 * you have to scroll back for.
 */
.app {
  display: grid;
  grid-template-columns: var(--nav-width) minmax(0, 1fr);
  min-height: 100vh;
}

/* The launcher stands alone: no column, because it is a column made of tiles.
   One class rather than a second layout file — the frame is the same frame,
   with one track fewer. */
.app.solo { grid-template-columns: minmax(0, 1fr); }

/* ── The navigation column ────────────────────────────────────────── */

.sidebar {
  position: sticky;
  top: 0;
  align-self: start;
  height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--nav-bg);
  color: var(--nav-ink);
  overflow: hidden auto;
  scrollbar-width: thin;
}

/* Whose console this is. The one solid red in the working screens, and it is
   at the top of the column rather than across the page: identity belongs
   beside the navigation, not in the operator's eye all day. */
.brand {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  height: var(--topbar-h);
  flex: none;
  padding: 0 var(--sp-4);
  background: var(--brand-bar);
  color: #fff;
  text-decoration: none;
}

.brand:hover { color: #fff; background: var(--brand); }
/* The project's mark, painted THROUGH the asset as a mask rather than dropped
   in as an <img>.
 *
 * One file, and it takes the colour of whatever it sits beside. That is the
 * whole reason for the technique: the mark appears on the red bar at the top
 * of the column and on white paper at the top of the launcher, and
 * `mark.svg` carries a red stroke of its own -- so on the bar it was a red
 * mark on a red bar, which is to say no mark at all. An <img> is an isolated
 * document and `currentColor` cannot reach inside it; a mask only reads the
 * asset's alpha, so the colour is decided out here.
 *
 * The alternative was a second white copy of the artwork, which is two files
 * that have to be redrawn together and will not be. */
.mark {
  display: block;
  flex: none;
  width: 20px;
  height: 20px;
  background: currentColor;
  -webkit-mask: url(/assets/img/mark.svg) center / contain no-repeat;
          mask: url(/assets/img/mark.svg) center / contain no-repeat;
}

.brand-name {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  white-space: nowrap;
}

.nav-groups { flex: 1; padding: var(--sp-3) 0; }

.nav-group { margin-top: var(--sp-4); }

.nav-group-title {
  margin: 0 0 var(--sp-1);
  padding: 0 var(--sp-4);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--nav-ink-dim);
}

.nav-item {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 7px var(--sp-4);
  border-inline-start: 3px solid transparent;
  color: var(--nav-ink);
  font-size: 13.5px;
  text-decoration: none;
  white-space: nowrap;
}

.nav-item:hover { background: var(--nav-hover); color: #fff; }

/* An entry the menu commits to that this build does not have. Dimmed, not
   hidden -- see nav.js -- and it must not respond to a hover, because a row
   that lights up under the pointer is a row that promises a click. */
.nav-item.soon {
  color: var(--nav-ink-dim);
  cursor: default;
}
.nav-item.soon:hover { background: none; color: var(--nav-ink-dim); }

.nav-soon {
  margin-inline-start: auto;
  padding-inline-start: var(--sp-2);
  font-size: 10px;
  letter-spacing: .08em;
  text-transform: uppercase;
  opacity: .7;
}

/* Where you are: the accent, which is the same colour as the thing you press.
   The two never appear together on one control, so one meaning each. */
.nav-item[aria-current="page"] {
  background: var(--nav-active);
  border-inline-start-color: var(--accent);
  color: #fff;
  font-weight: 600;
}

.nav-glyph {
  width: 16px;
  text-align: center;
  font-size: 13px;
  opacity: .8;
}

.nav-foot {
  flex: none;
  padding: var(--sp-3) var(--sp-4);
  border-top: 1px solid var(--nav-rule);
  font-size: 12px;
  color: var(--nav-ink-dim);
}

.nav-foot a { color: var(--nav-ink); text-decoration: none; }
.nav-foot a:hover { color: #fff; text-decoration: underline; }
.nav-foot .build { display: block; margin-top: var(--sp-1); font-size: 11px; }

/* ── The toolbar above the page ───────────────────────────────────── */

.main { display: flex; flex-direction: column; min-width: 0; }

.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  height: var(--topbar-h);
  flex: none;
  padding: 0 var(--sp-5);
  background: var(--paper);
  border-bottom: 1px solid var(--rule);
}

/* Where you are, as a trail. It is the only place the module name appears
   once the column is a fixed set of links. */
.crumbs {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  min-width: 0;
  flex: 1;
  font-size: 13px;
  color: var(--ink-60);
}

.crumbs a { color: var(--ink-60); text-decoration: none; }
.crumbs a:hover { color: var(--brand); }
.crumbs b { color: var(--ink); font-weight: 600; }
.crumbs .sep { color: var(--ink-25); }

.topbar-right { display: flex; align-items: center; gap: var(--sp-2); }

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--radius-field);
  background: none;
  color: var(--ink-60);
  font-size: 15px;
  line-height: 1;
  text-decoration: none;   /* the alert bell is an <a>; keep the glyph unruled */
  cursor: pointer;
}

.icon-btn:hover { background: var(--tint); color: var(--ink); }

.nav-toggle { display: none; }

/* The alert bell. A count that is not zero is the loudest thing in the bar,
   which is the point of putting it there. */
.bell { position: relative; }

.bell-count {
  position: absolute;
  top: -2px;
  inset-inline-end: -2px;
  min-width: 16px;
  padding: 0 4px;
  border-radius: 8px;
  background: var(--err);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  line-height: 16px;
}

.bell-count:empty { display: none; }

/* Who is signed in, and the menu under it. */
.usermenu { position: relative; }

.user-btn {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  height: 34px;
  padding: 0 var(--sp-2);
  border: 1px solid transparent;
  border-radius: var(--radius-field);
  background: none;
  font: inherit;
  color: var(--ink);
  cursor: pointer;
}

.user-btn:hover { background: var(--tint); }

.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  flex: none;
  border-radius: 50%;
  background: var(--brand);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .02em;
}

.user-who { display: flex; flex-direction: column; line-height: 1.2; text-align: start; }
.user-who b { font-size: 12.5px; font-weight: 600; }
.user-who span { font-size: 11px; color: var(--ink-60); }

.menu {
  position: absolute;
  top: calc(100% + 6px);
  inset-inline-end: 0;
  z-index: 30;
  min-width: 190px;
  padding: var(--sp-1);
  border: 1px solid var(--rule);
  border-radius: var(--radius-field);
  background: var(--paper);
  box-shadow: var(--shadow-pop);
}

.menu a, .menu button {
  display: block;
  width: 100%;
  padding: 7px var(--sp-3);
  border: 0;
  border-radius: 4px;
  background: none;
  color: var(--ink);
  font: inherit;
  text-align: start;
  text-decoration: none;
  cursor: pointer;
}

.menu a:hover, .menu button:hover { background: var(--tint); color: var(--ink); }
.menu hr { margin: var(--sp-1) 0; border: 0; border-top: 1px solid var(--rule-soft); }
.menu .menu-meta { padding: var(--sp-2) var(--sp-3); font-size: 11.5px; color: var(--ink-60); }

/* The language switcher (SW-01). A button of its own in the toolbar rather
   than a row inside the account menu: the person reaching for it cannot read
   the screen, and a control behind somebody's own name is a control they do
   not find. The subtag is on the button -- EN, VI -- because that is the part
   recognisable without reading anything. */
.langmenu { position: relative; }

.lang-btn {
  width: auto;
  gap: 4px;
  padding: 0 var(--sp-2);
}
.lang-btn .lang-globe { font-size: 13px; }
.lang-btn .lang-code { font-size: 11.5px; font-weight: 700; letter-spacing: .04em; }

.lang-list { min-width: 220px; }

/* The tick column is always there, occupied or not: rows that shifted
   sideways as the choice moved would read as the menu redrawing itself. */
/* Written under .lang-list because `.menu button` above sets display:block
   and would otherwise outweigh a single class. */
.lang-list .lang-row {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
}
.lang-row .tick {
  flex: none;
  width: 1em;
  color: var(--brand);
  font-weight: 700;
}
.lang-row.on .lang-name { font-weight: 600; }
.lang-row .lang-name small {
  display: block;
  margin-block-start: 1px;
  color: var(--ink-60);
  font-size: 11.5px;
  line-height: 1.35;
}

/* ── The page ─────────────────────────────────────────────────────── */

.page {
  flex: 1;
  min-width: 0;
  padding: var(--sp-5);
  /* Room for the alert dock, which is anchored to the bottom of the window. */
  padding-bottom: 96px;
}

/* The strip a tabbed menu entry draws above its page: People | User groups.
   A band under the toolbar, drawn by Chrome.tabs() as a sibling of .page --
   the heading names the view and the strip is how you chose it, which is the
   order those two are read in. It sits beside the page rather than inside it
   because the master-data screens clear .page on every route change; see the
   note in nav.js. */
.page-tabs {
  display: flex;
  gap: var(--sp-1);
  flex: none;
  padding: 0 var(--sp-5);
  background: var(--paper);
  border-bottom: 1px solid var(--rule);
  /* More tabs than the width holds — five of them on a phone — must be
     reachable rather than clipped off the end, so the strip scrolls sideways
     when it has to. The scrollbar appears only when it does, so a strip that
     fits (every one of them on a desktop) looks exactly as before. */
  overflow-x: auto;
  scrollbar-width: thin;
}

.page-tab {
  /* Do not let a tab squeeze thinner than its label: a strip that shrinks its
     tabs to fit is one where the strip scrolls but each tab is unreadable. */
  flex: 0 0 auto;
  padding: 7px var(--sp-3);
  border-bottom: 2px solid transparent;
  color: var(--ink-60);
  font-size: 13.5px;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}

.page-tab:hover { color: var(--ink); }

/* The accent underneath, the same mark the column uses for where you are. */
.page-tab[aria-current="page"] {
  border-bottom-color: var(--brand);
  color: var(--ink);
}

.page-head {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-4);
  flex-wrap: wrap;
  margin-bottom: var(--sp-4);
}

.page-head > div:first-child { flex: 1; min-width: 0; }

.page-head h1 { font-size: 20px; }

.page-sub {
  margin: 2px 0 0;
  max-width: var(--measure);
  font-size: 13px;
  color: var(--ink-60);
}

.page-actions { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }

/* Stacked cards, one gap between them, wherever they are. */
.stack { display: flex; flex-direction: column; gap: var(--sp-4); }

/* Two columns where a page has a main object and its side facts. Collapses to
   one, because at that width neither column is readable. */
.split { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: var(--sp-4); align-items: start; }

@media (max-width: 1100px) { .split { grid-template-columns: minmax(0, 1fr); } }

/* ── Narrow ──────────────────────────────────────────────────────── */

@media (max-width: 900px) {
  .app { grid-template-columns: minmax(0, 1fr); }

  .sidebar {
    position: fixed;
    z-index: 40;
    inset-inline-start: 0;
    top: 0;
    width: var(--nav-width);
    /* Off the START edge, whichever edge that is. `translateX` is physical,
       so the direction is flipped for a right-to-left script rather than
       left as a drawer that slides out of the wrong side. */
    transform: translateX(-100%);
    transition: transform .16s ease-out;
    box-shadow: var(--shadow-pop);
  }

  [dir="rtl"] .sidebar { transform: translateX(100%); }
  .app.nav-open .sidebar { transform: none; }
  .nav-toggle { display: inline-flex; }
  /* Nothing to open on the launcher: it has no column. A button that
     does nothing is worse than no button. */
  .app.solo .nav-toggle { display: none; }
  .page { padding: var(--sp-4); padding-bottom: 96px; }
}

/* ── Phone ────────────────────────────────────────────────────────────
 *
 * At a phone's width the toolbar had more in it than the width could hold:
 * the trail, the language button, the bell and the signed-in name all at
 * once, so the trail ran under the controls to its end. The bar keeps the
 * things a thumb reaches for — the drawer button, the bell, the language,
 * the account — and gives up what a phone can spare.
 */
@media (max-width: 640px) {
  /* The trail collapses to the page you are on. Its ancestors are one tap on
     the drawer away, and the heading below already names the page again, so
     on a phone the room goes to nothing rather than to a trail that spills. */
  .crumbs { overflow: hidden; }
  .crumbs > :not(b) { display: none; }
  .crumbs > b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  /* The account is just its avatar here; the name and role are inside the menu
     it opens. The name is what the bar can spare — it is the one thing in it
     the person already knows. */
  .user-who { display: none; }
  .user-btn { padding-inline: 3px; }

  /* Tighter gutters so the controls that remain are not pushed together. */
  .topbar { padding: 0 var(--sp-3); gap: var(--sp-2); }

  /* The tab strip shares the page's gutter rather than the desktop's wider
     one, so the first tab lines up with the heading below it. */
  .page-tabs { padding: 0 var(--sp-3); }
}
