/* SAB Portal — The page frame: the window, the sidebar, the account block, the page header.
 * Chrome, in the sense portal/ uses the word — furniture that every signed-in
 * page carries and no page owns.
 *
 * One of the files listed in layers.css; read that first. Every rule below
 * is in the `app` cascade layer, so it beats Pico without needing to be
 * more specific than Pico. Sizes come from tokens.css and nowhere else. */

@layer app {

/* --- Page frame ---------------------------------------------------------
 *
 * Two columns: the navigation panel, and everything else. The panel used to
 * be a bar across the top, and the move down the side is a layout change and
 * not a redesign — the same surface, the same colours, the same two menus.
 *
 * What it buys: the sections stand one under another where an operations
 * reader looks for them, each one is a full row to press instead of a word in
 * a line, the list has room to grow past the four it holds today, and the
 * band a bar was taking across the top of every page goes back to the page.
 */
.sab-shell {
  display: flex;
  align-items: flex-start;
  min-height: 100vh;
  background: var(--sab-page-bg);
}

/* The shell's other state: no reader signed in, so no panel, and the page
 * gets the whole window. The sign-in page is the one that wants this. */
.sab-shell-bare {
  display: block;
  /* The sign-in photograph is on the body, behind this. */
  background: transparent;
}

/* The column: white like the top bar and edged by the same hairline, so the
 * two meet in one corner instead of two overlapping shadows. Sticky and
 * full-height, so the sections stay put while a long listing scrolls. */
.sab-sidebar {
  position: sticky;
  top: 0;
  flex: none;
  display: flex;
  flex-direction: column;
  gap: var(--sab-gap-loose);
  width: var(--sab-sidebar-width);
  height: 100vh;
  /* No padding across the panel, only down it. Each group sets its own inset,
   * and they all set the same one, so the wordmark, every section word and
   * the reader's name start on one line down the column. */
  padding: 0 0 var(--sab-block-wide);
  background: var(--sab-bar-bg);
  border-right: var(--sab-hairline) solid var(--sab-rule);
  /* Sticky makes the column its own stacking context. Lifted, so the
   * Feedback panel it opens over the page lands above the map. */
  z-index: var(--sab-layer-panel);
}

/* Whose portal it is. A wordmark and the way home, so it has to look like a
 * link: the page's own colour at rest and the action colour under the
 * pointer. Where you *are* is said by the Overview row below it, which is a
 * row like every other — a wordmark doing double duty as the current section
 * is a mark nobody reads. */
.sab-sidebar-brand {
  display: flex;
  flex: none;
  align-items: center;
  height: var(--sab-brand-height);
  font-size: var(--sab-text-lead);
  font-weight: var(--sab-weight-strong);
  letter-spacing: -0.01em;
  padding: 0 var(--sab-sidebar-inset);
  border-bottom: var(--sab-hairline) solid var(--sab-rule);
}

.sab-sidebar-brand a {
  color: var(--sab-ink);
  text-decoration: none;
}

.sab-sidebar-brand a:hover,
.sab-sidebar-brand a:focus-visible {
  color: var(--pico-primary);
}

.sab-sidebar-brand span {
  color: var(--pico-muted-color);
  font-weight: var(--sab-weight-normal);
}

/* Pico lays a `nav` out as a row with its groups pushed apart, which is what
 * a bar wants and the opposite of what a column wants: the list shrank to its
 * words and sat in the middle of the panel. A block, and the list fills it. */
.sab-sidebar-nav {
  display: block;
}

/* Pico pulls the first list in a nav out to the left by its own spacing, to
 * line a bar's first word up with the edge of the page. Here that is the
 * panel's padding, and the rows hung over it. Wound back, with a selector
 * specific enough to beat `nav ul:first-of-type`. */
.sab-sidebar-nav .sab-nav {
  margin: 0;
}

/* The sections. A list, because that is what it is — a screen reader announces
 * how many places there are to go before the reader steps through them. */
.sab-nav {
  width: 100%;
  display: flex;
  flex-direction: column;
  /* Pico centres a nav list, because a nav list is a row. Turned on its side
   * that centring is what shrinks every section to the width of its own word
   * and floats it in the middle of the column. */
  align-items: stretch;
  /* A press apart, not a hairline apart. Four sections a quarter of a step
   * from each other read as one block with lines through it, and the fill a
   * row takes when it is hovered then lands against the row above it. */
  gap: var(--sab-gap);
  margin: 0;
  padding: 0;
  list-style: none;
}

.sab-nav li {
  padding: 0;
}

/* A row, not a word: the whole width is the target, which is the one thing a
 * column of sections can give a reader that a row of them cannot.
 *
 * Held off the panel edge by a margin of its own and rounded, so the shape a
 * row takes when it is hovered or current is a shape with air round it. A
 * fill that runs edge to edge is a band, and four bands stacked with a gap
 * between them read as a striped panel rather than as four things to press. */
.sab-nav a {
  display: flex;
  align-items: center;
  gap: var(--sab-gap);
  /* Zero down the page, and not Pico's default: a nav link there carries a
   * negative vertical margin, meant to pull a link back into a bar's own
   * line. In a column that margin is rows overlapping each other by half a
   * step, which is visible the moment one of them is hovered. */
  margin: 0 var(--sab-gap);
  padding: var(--sab-gap) var(--sab-gap);
  border-radius: var(--sab-radius);
  color: var(--pico-muted-color);
  font-size: var(--sab-text-body);
  line-height: 1.4;
  text-decoration: none;
}

/* Hovering is lighter than being there. The panel is white, so the two greys
 * go in the order a reader expects: a faint one under the pointer, a firmer
 * one under the section they are on. The other way round — a white current
 * row lifted off a white panel — reads as a card that has come loose. */
.sab-nav a:hover,
.sab-nav a:focus-visible {
  background: var(--sab-quiet-bg);
  color: var(--sab-ink);
}

/* Where you are: the accent's tint and a heavier word, so it reads in colour
 * and in greyscale. */
.sab-nav a[aria-current="page"] {
  background: var(--sab-action-bg);
  color: var(--sab-action);
  font-weight: var(--sab-weight-strong);
}

/* The icon beside the word. Never the meaning on its own — the word is always
 * there — so it stays the row's own colour and gets no weight of its own. */
.sab-nav .sab-tab-icon {
  width: 1.1rem;
  height: 1.1rem;
  color: inherit;
}

/* A named group of shortcuts under the sections, its words starting on the
 * same line as every row's icon. */
.sab-nav-group {
  margin: var(--sab-block) 0 var(--sab-gap);
  padding: 0 var(--sab-sidebar-inset);
  color: var(--sab-action);
  font-size: var(--sab-text-micro);
  font-weight: var(--sab-weight-strong);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* A shortcut's mark: a dot in the icon's square, so its word lines up with
 * the sections' words above it. */
.sab-nav-dot {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 1.1rem;
  height: 1.1rem;
}

.sab-nav-dot::before {
  content: "";
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
  background: var(--sab-action);
}

/* The reader's own corner: which language, and who they are. At the foot of
 * the column, pushed there by its own margin, because neither is a place to
 * go and a section list that ends in two controls reads as six sections. */
.sab-sidebar-end {
  display: flex;
  flex-direction: column;
  gap: var(--sab-gap-tight);
  margin-block-start: auto;
  /* The same inset as a section row, so every icon and the avatar share one line. */
  padding: var(--sab-gap) var(--sab-gap) 0;
  border-top: var(--sab-hairline) solid var(--sab-rule);
}

/* One row, the width of the column: the reader's name is the control, and
 * what it opens holds the language and the way out. Two stacked controls was
 * two decisions in the place a reader looks once. */
.sab-sidebar-end .sab-account,
.sab-sidebar-end .sab-account.dropdown > summary:not([role]) {
  display: flex;
  width: 100%;
}

/* No box round it: a name and a disc that light up under the pointer, the way
 * every section above it does. */
.sab-sidebar-end .sab-account.dropdown > summary:not([role]) {
  align-items: center;
  gap: var(--sab-gap);
  min-height: 0;
  padding: var(--sab-gap-tight) var(--sab-gap) var(--sab-gap-tight) var(--sab-gap-tight);
  border: 0;
  border-radius: var(--sab-radius);
  background: transparent;
  color: var(--sab-ink);
  font-size: var(--sab-text-body);
  letter-spacing: normal;
}

.sab-sidebar-end .sab-account.dropdown > summary:not([role]):hover,
.sab-sidebar-end .sab-account.dropdown > summary:not([role]):focus-visible,
.sab-sidebar-end .sab-account[open].dropdown > summary:not([role]) {
  background: var(--sab-quiet-bg);
}

/* The menu opens upwards, so the chevron points the way it will open. */
.sab-sidebar-end .sab-account.dropdown > summary::after {
  height: 1rem;
  opacity: 0.6;
  transform: rotate(180deg);
}

.sab-sidebar-end .sab-account[open].dropdown > summary::after {
  transform: rotate(0);
}

/* The overview's KPI badge, round: the accent's tint, the accent's ink. */
.sab-sidebar-end .sab-avatar {
  width: var(--sab-control-tile);
  height: var(--sab-control-tile);
  background: var(--sab-action-bg);
  color: var(--sab-action);
  font-size: var(--sab-text-label);
}

.sab-sidebar-end .sab-account .sab-who {
  /* Takes the row, so the chevron lands at the right edge, not on the name. */
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  min-width: 0;
  max-width: none;
  line-height: 1.25;
}

.sab-who-name {
  overflow: hidden;
  text-overflow: ellipsis;
  font-weight: var(--sab-weight-medium);
}

.sab-who-role {
  color: var(--pico-muted-color);
  font-size: var(--sab-text-micro);
}

/* The panel the name opens. More air than a list of options needs, because
 * this one is read rather than scanned: who you are, which language, and the
 * way out are three different kinds of thing and the spacing is what says so.
 * A softer corner than the row under it, so it reads as something in front of
 * the page and not as the row having grown. */
.sab-sidebar-end .sab-account.dropdown > summary + ul {
  min-width: 13rem;
  margin-bottom: var(--sab-gap);
  padding: var(--sab-gap);
  border-radius: var(--sab-radius-panel);
}

.sab-sidebar-end .sab-language-choice,
.sab-sidebar-end .sab-account-action {
  padding: var(--sab-gap) var(--sab-gap-loose);
  font-size: var(--sab-text-body);
}

/* Who you are: a statement over the actions, with a rule under it and room
 * either side of the rule. */
.sab-sidebar-end .sab-account.dropdown > summary + ul li.sab-account-who {
  padding: var(--sab-gap) var(--sab-gap-loose) var(--sab-gap-loose);
  font-size: var(--sab-text-label);
}

.sab-sidebar-end .sab-account.dropdown > summary + ul li.sab-account-who + li {
  padding-top: var(--sab-gap);
}

/* The way out, set apart from the languages: changing language leaves you
 * where you are and signing out does not, and two rows that sit together
 * read as two of the same kind. */
.sab-sidebar-end .sab-account-languages + li {
  margin-top: var(--sab-gap);
  padding-top: var(--sab-gap);
  border-top: var(--sab-hairline) solid var(--sab-rule);
}

/* The languages inside the account menu. A row of this menu, drawn like the
 * other rows: no border round the group, no second background, because a
 * panel inside a panel is a menu that looks like two. */
.sab-account-languages {
  padding: 0;
}

.sab-language-form {
  display: flex;
  flex-direction: column;
  margin: 0;
}

/* The page beside the panel. `main` keeps Pico's own column so the text does
 * not run the full width of a wide window, but it is now centred in what is
 * left rather than in the window — which is what makes the two columns read
 * as one page. */
/* The column beside the navigation panel: the top bar, then the page. */
.sab-shell-page {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.sab-shell-page > main {
  flex: 1 1 auto;
  padding-block: var(--sab-block-wide);
  /* Not Pico's centred text column: a listing of ten columns wants the width.
   * Capped all the same, so a page on a wide monitor does not stretch its
   * cards across the whole of it. */
  width: 100%;
  max-width: var(--sab-page-max);
  padding-inline: var(--sab-block-loose);
  /* `min-width: 0`: a wide table inside a flex child otherwise refuses to
   * shrink, and the page scrolls sideways instead of the table. */
  min-width: 0;
}


/* --- The two menus in the sidebar ----------------------------------------
 *
 * Language and account. Both are Pico's `details.dropdown` — markup and
 * stylesheet and no script — and both are styled by the rules below rather
 * than by two sets that drift: two menus in the same row that open differently
 * read as two different pages.
 *
 * Neither is data. Each is set or read once and then not touched again, so at
 * rest they are as quiet as the text beside them and only the open one is
 * loud. The current language is marked by weight and contrast as well as by
 * tint, and carries aria-current, so the choice is legible in greyscale and to
 * a screen reader.
 */

.sab-language {
  display: inline-block;
  margin: 0;
}

.sab-language details,
.sab-account {
  margin: 0;
}

/* Compact: Pico sizes a summary like a form field, which is twice the height
 * the foot of the panel can spare. */
.sab-language details.dropdown > summary:not([role]),
.sab-account.dropdown > summary:not([role]) {
  display: inline-flex;
  align-items: center;
  gap: var(--sab-gap-tight);
  height: auto;
  /* One height for both, set here rather than left to whatever each one
   * happens to contain: the account menu holds a disc and the language menu
   * holds a flag, and two boxes side by side that miss each other's height by
   * three pixels look like a mistake rather than like a pair. */
  min-height: 1.75rem;
  padding: var(--sab-gap-tight) var(--sab-gap);
  border: 1px solid var(--sab-rule);
  border-radius: var(--pico-border-radius);
  /* Nothing behind it, so the bar shows through. A filled box on a bar that is
   * itself a surface reads as a form field waiting to be typed in, and neither
   * of these is one — the outline is enough to say it can be pressed. */
  background: transparent;
  color: var(--pico-muted-color);
  font-size: var(--sab-text-small);
  letter-spacing: 0.04em;
  line-height: 1.5;
}

/* Not a link. The summary is the one control in the panel that opens
 * something, and at rest it is drawn as quietly as the text beside it.
 *
 * `--sab-row` and not `--sab-quiet-bg` for the fill: on the panel those two are
 * the same colour, so the quiet grey would be a hover that does nothing. The
 * row colour is the page's own surface and steps away from the bar in both
 * themes. */
.sab-language details.dropdown > summary:not([role]):hover,
.sab-language details.dropdown > summary:not([role]):focus-visible,
.sab-language details[open].dropdown > summary:not([role]),
.sab-account.dropdown > summary:not([role]):hover,
.sab-account.dropdown > summary:not([role]):focus-visible,
.sab-account[open].dropdown > summary:not([role]) {
  background: var(--sab-row);
  color: var(--sab-ink);
}

/* Right-aligned, because the switcher is in the right-hand corner in both
 * places it appears and a list that opens leftwards from there runs off the
 * page. */
.sab-language details.dropdown > summary + ul,
.sab-account.dropdown > summary + ul {
  right: 0;
  left: auto;
  /* Over the map. Leaflet's own panes start at 200 and Pico gives a dropdown
   * 99, so on the dashboard the list opened underneath the fleet — see the
   * layer scale in the token block. */
  z-index: var(--sab-layer-panel);
  /* Pico sets `width: 100%`, which is the width of the summary — a language
   * name is longer than that, and the list does not wrap, so the words would
   * spill past the right edge of their own panel. The box grows to its
   * contents and never shrinks below the summary. */
  width: max-content;
  min-width: 100%;
  /* Clear of the summary rather than welded to it: the list is a thing that
   * opened, and it is read against the page and not against the button. */
  margin-top: var(--sab-gap-tight);
  padding: var(--sab-gap-tight);
  border-radius: var(--sab-radius);
  box-shadow: var(--sab-panel-shadow);
}

/* Both menus stand at the foot of a column against the left edge of the
 * window, so both of Pico's defaults are wrong there: a list that opened
 * downwards would open past the bottom of the window, and one anchored to its
 * summary's right edge would run off the left of the screen. Upwards, and
 * from the left. */
.sab-sidebar-end details.dropdown > summary + ul {
  top: auto;
  bottom: 100%;
  right: auto;
  left: 0;
  margin-top: 0;
  margin-bottom: var(--sab-gap-tight);
}

/* The row is the button, so the list item carries no space of its own — two
 * paddings on one row is what makes a menu look loose. */
.sab-language details.dropdown > summary + ul li,
.sab-account.dropdown > summary + ul li {
  padding: 0;
}

.sab-language-choice,
.sab-account-action {
  display: flex;
  align-items: center;
  gap: var(--sab-gap);
  width: 100%;
  margin: 0;
  padding: var(--sab-gap-tight) var(--sab-gap);
  border: 0;
  border-radius: var(--sab-radius);
  background: transparent;
  /* Not `--pico-color`: inside a button that is the colour of text on a filled
   * primary button, which is white — so every language except the one the
   * reader is already on rendered as a flag and no word at all. The words are
   * the point; a flag is a country and not a language. */
  color: var(--sab-ink);
  font-size: var(--sab-text-meta);
  line-height: 1.5;
  text-align: left;
  white-space: nowrap;
}

.sab-language-choice:hover,
.sab-language-choice:focus-visible,
.sab-account-action:hover,
.sab-account-action:focus-visible {
  background: var(--sab-quiet-bg-hover);
  color: var(--sab-ink);
}

.sab-language-current {
  background: var(--sab-selected-bg);
  color: var(--sab-selected);
  font-weight: var(--sab-weight-strong);
}

/* Which one you are on, as a mark and not only as a tint. `aria-current` says
 * it to a screen reader; this says it to everyone else, and it says it at the
 * end of the row so the two languages still start on the same line. */
.sab-language-current::after {
  content: "\2713";
  margin-left: auto;
  padding-left: var(--sab-gap);
  color: var(--sab-action);
}

/* The flag beside the language. It never carries the meaning on its own — a
 * flag is a country and not a language — so the name stays beside it and stays
 * the thing a reader reads. A language with no flag drawn for it simply shows
 * its name; see components/language_flag.html. */
.sab-flag {
  display: block;
  flex: none;
  width: 1.05rem;
  height: auto;
  border-radius: 1px;
}

/* --- Account -------------------------------------------------------------
 *
 * The other menu in the row. It exists because the reader's name used to be a
 * word with nothing to press: everything that is about *you* rather than about
 * the fleet is behind it, which at the moment is exactly one thing, and is the
 * place the next one goes.
 */

.sab-account .sab-who {
  /* The name is why the control is there, so it is read as text and not as a
   * caption under an initial. */
  color: inherit;
  font-size: var(--sab-text-label);
  max-width: 9rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* An initial in a disc. Decoration over the name and never instead of it: two
 * colleagues share a letter, and nobody shares a username. `aria-hidden`, so a
 * screen reader hears the name once. */
.sab-avatar {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 1.25rem;
  height: 1.25rem;
  border-radius: 50%;
  background: var(--sab-selected-bg);
  color: var(--sab-selected);
  font-size: var(--sab-text-micro);
  font-weight: var(--sab-weight-strong);
  letter-spacing: 0;
}

/* Who the portal thinks you are, spelled out where the summary had to
 * truncate it. A statement and not a control, so it is not in the menu's
 * hover colour and cannot be pressed by mistake. */
/* Wound past `summary + ul li { padding: 0 }` above, which is the rule that
 * makes every *row* the button it holds. This row holds no button. */
.sab-account.dropdown > summary + ul li.sab-account-who {
  margin: 0;
  padding: var(--sab-gap-tight) var(--sab-gap);
  color: var(--pico-muted-color);
  font-size: var(--sab-text-meta);
  line-height: 1.5;
  white-space: nowrap;
}

.sab-account-who strong {
  color: var(--sab-ink);
  font-weight: var(--sab-weight-medium);
}

.sab-account.dropdown > summary + ul li.sab-account-who + li {
  border-top: var(--sab-hairline) solid var(--sab-rule);
  margin-top: var(--sab-gap-tight);
  padding-top: var(--sab-gap-tight);
}

/* The form is a wrapper round one button and must not add a second box round
 * it — a row in this menu is the button and nothing else. */
.sab-account form {
  margin: 0;
}

/* --- Page header -------------------------------------------------------- */

.sab-page-header {
  margin-bottom: 0.9rem;
}

.sab-page-header h2 {
  margin-bottom: var(--sab-gap-tight);
  letter-spacing: var(--sab-tracking-tight);
}

.sab-counts {
  color: var(--pico-muted-color);
  font-size: var(--sab-text-body);
  margin: 0;
}

/* A section's name, and the one thing to do with the section, on one line. */
.sab-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sab-gap-loose);
}

/* Styled like a figure card's "Show all", so every card's link reads alike. */
.sab-section-head a {
  flex: none;
  font-size: var(--sab-text-meta);
  font-weight: var(--sab-weight-medium);
  text-decoration: none;
}

.sab-section-head a:hover,
.sab-section-head a:focus-visible {
  text-decoration: underline;
}

/* --- The card surface ---------------------------------------------------
 *
 * Every card in the portal stands on this one ground, border and corner. A
 * card rule elsewhere sets its layout and padding, never its surface. */
.sab-kpi,
.sab-panel,
.sab-card,
.sab-card-row,
.sab-end-card,
.sab-audio,
.sab-table-scroll {
  border: var(--sab-hairline) solid var(--sab-card-edge);
  border-radius: var(--sab-radius-card);
  background: var(--sab-row);
  box-shadow: var(--sab-card-shadow);
}

}
