Novus Technologies Novus Technologies design kit v0.9.0
Menu

Layout

App shell

Full-bleed header and nav whose content aligns to the shared 1200px column.

.appbar · .appbar__inner · .appnav · .appnav__inner · .appmain · .appheader

Novus Technologies Novus Technologies console

Main content aligns to the same centered column as the bars above.

Header + nav + main (shared column)
<div style="border:1px solid var(--border);border-radius:var(--radius-md);overflow:hidden">
  <header class="appbar">
    <div class="appbar__inner">
      <div class="brandlock">
        <img class="brandlogo--light" src="../logos/Novus_Logo_Colour_transparent.png" alt="Novus Technologies">
        <img class="brandlogo--dark" src="../logos/Novus_Logo_White_transparent.png" alt="Novus Technologies">
        <span class="appname">console</span>
      </div>
      <button class="btn btn--ghost btn--sm">Sign out</button>
    </div>
  </header>
  <nav class="appnav">
    <div class="appnav__inner nav" style="border-bottom:0">
      <a href="#" aria-current="page">Dashboard</a>
      <a href="#">Reports</a>
      <a href="#">Settings</a>
    </div>
  </nav>
  <main class="appmain" style="padding-block:var(--space-4)">
    <p class="muted" style="margin:0">Main content aligns to the same centered column as the bars above.</p>
  </main>
</div>
novaplan
Live Novus Technologies Novus Technologies
Internal-tool header (two-mark rule)
<div class="appheader" style="border:1px solid var(--border);border-radius:var(--radius-md);padding:var(--space-3) var(--space-4)">
  <div class="appheader__left">
    <img src="../logos/lockups/novaplan.png" alt="novaplan" style="height:var(--space-6);width:auto">
  </div>
  <div class="appheader__right">
    <span class="badge badge--success"><span class="badge__dot"></span> Live</span>
    <span class="appheader__sep"></span>
    <span class="appheader__endorse">
      <img class="brandlogo--light" src="../logos/Novus_Logo_Colour_transparent.png" alt="Novus Technologies">
      <img class="brandlogo--dark" src="../logos/Novus_Logo_White_transparent.png" alt="Novus Technologies">
    </span>
  </div>
</div>

What sits at the far right

The account menu is the last element in a console header, flush to the gutter at every width, and the Novus endorsement mark sits immediately before it. A release gate enforces that nothing is placed to its right.

This diverges deliberately from section 4c of the master token file, which places the Novus master lockup at the far right as the endorsement. That section governs brand surfaces. Application chrome puts the operator's own account where operators look for it, which is the far right. The token file is the upstream master and is not edited to resolve this; the divergence is recorded in the kit's constitution instead.

operations · admin
ops.admin
Operations Adminops.admin@novustech.com.sg
Profile
Theme
Console header: app switcher, menu toggle, product lockup, endorsement, user menu
  <div style="border:1px solid var(--border);border-radius:var(--radius-md);min-height:17rem">
    <input type="checkbox" id="navtoggle-shell" class="navtoggle__input" aria-label="Show or hide the menu">
    <header class="appbar">
  <div class="appbar__inner appheader">
    <div class="appheader__left">
      <novus-app-switcher current="novapay" launcher="https://workspace.novustech.dev" catalog="../demos/app-switcher/sample-catalog.json"></novus-app-switcher>
      <label for="navtoggle-shell" class="btn btn--ghost btn--sm toggle44 navtoggle" title="Menu"><svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h16"/></svg></label>
      <span class="theme-novapay vlogo"><svg class="vmark" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3.5" y="6" width="17" height="12" rx="2"/><line x1="3.5" y1="9.5" x2="20.5" y2="9.5"/><rect x="6" y="12" width="3.6" height="3" rx="0.6"/></svg><span class="wm"><span class="nm">nova</span><span class="sf">pay</span></span></span>
      <span class="muted appsuffix">operations · admin</span>
    </div>
    <div class="appheader__right">
      <span class="appheader__endorse"><span class="brandmark" role="img" aria-label="Novus Technologies"></span></span>
      <span class="appheader__sep"></span>
      <details class="userdd" data-dismiss>
        <summary class="btn btn--ghost btn--sm userdd__trigger"><svg class="icon icon--sm" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="8" r="3.75"/><path d="M4.75 20a7.25 7.25 0 0 1 14.5 0"/></svg><span class="userdd__name truncate">ops.admin</span><svg class="icon icon--sm" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg></summary>
        <div class="card userdd__menu">
          <div class="userdd__who"><b>Operations Admin</b><span class="muted">ops.admin@novustech.com.sg</span></div>
          <a class="userdd__item" href="settings-layout.html#sl-profile"><svg class="icon icon--sm" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="8" r="3.75"/><path d="M4.75 20a7.25 7.25 0 0 1 14.5 0"/></svg> Profile</a>
          <div class="userdd__row"><span class="muted">Theme</span><button type="button" class="btn btn--ghost btn--sm toggle44 themetoggle" data-theme-toggle aria-label="Toggle light and dark theme"><svg class="icon ic-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 14.5A8 8 0 0 1 9.5 4a8 8 0 1 0 10.5 10.5Z"/></svg><svg class="icon ic-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.3 5.3l1.4 1.4M17.3 17.3l1.4 1.4M18.7 5.3l-1.4 1.4M6.7 17.3l-1.4 1.4"/></svg></button></div>
          <div class="userdd__foot"><a class="btn btn--secondary btn--sm" href="signed-out-page.html"><svg class="icon icon--sm" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 4H6a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h4"/><path d="m15 8 4 4-4 4M19 12H9"/></svg> Sign out</a></div>
        </div>
      </details>
    </div>
  </div>
</header>
  </div>

Usage

  • The bars are full-bleed (background and hairline span the viewport) but their inner content aligns to the shared 1200px column, use the __inner wrappers.
  • External surfaces lead with the Novus master lockup on the left, prominent. Internal tools invert it: the app's own lockup leads far left, the Novus master lockup endorses far right, the two marks are never adjacent.
  • Below 520px the divider drops and the endorsement steps down to 20px, it never disappears.
  • Ship the persisted theme toggle and apply it before paint (js/novus-theme.js): in the header bar on sites, inside the user menu on consoles.
  • Consoles lead with the app switcher, then the menu toggle and the product lockup, and end with the Novus endorsement, a divider, and the user menu; see Side navigation. Nothing sits to the left of the app switcher or to the right of the user menu.

CSS

These rules ship in the console pattern layer, admin-kits/shared/novus-admin.css, which this site and every Admin Kit flavor load after tokens.css. Copy the whole layer, or only the sections below; every value is a token.

@pattern console-shell
.adminwrap { min-height: 100vh; min-height: 100dvh; display: flex; flex-direction: column; }
.demobar { background: var(--bg-subtle); border-bottom: 1px solid var(--border); padding: var(--space-1) var(--gutter); font-size: var(--text-xs); color: var(--text-secondary); text-align: right; }
.appbar__inner { max-width: none; font-size: var(--text-sm); line-height: var(--lh-sm); }
.appheader { flex-wrap: nowrap; }
.appheader__left { min-width: 0; gap: var(--space-2); }
.appheader__right { min-width: 0; }
.appsuffix { font-size: var(--text-sm); white-space: nowrap; }
.appname { font-weight: var(--weight-bold); font-size: var(--text-lg); color: var(--text); }
/* A 44px target, anywhere. Named for the rule it satisfies rather than the
   menu toggle it was first written for. .toggle44 is the former name and
   keeps working, so nothing already shipped breaks. */
.target44, .toggle44 { min-height: 2.75rem; min-width: 2.75rem; }
.navtoggle { padding: 0; cursor: pointer; }
.navtoggle__input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.navtoggle__input:focus-visible ~ .appbar .navtoggle { box-shadow: var(--focus-ring); }

/* Endorsement: placed asset via tokens, dark swap under BOTH triggers */
.brandmark { display: block; height: var(--logo-height); width: 132px; background: var(--logo-master-colour) center/contain no-repeat; flex: 0 0 auto; }
[data-theme="dark"] .brandmark { background-image: var(--logo-master-white); }
@media (prefers-color-scheme: dark) { :root:not([data-theme]) .brandmark { background-image: var(--logo-master-white); } }
[data-theme="light"] .brandmark { background-image: var(--logo-master-colour); }

.adminbody { flex: 1; width: 100%; padding: var(--space-5) var(--gutter) var(--space-8); font-size: var(--text-sm); line-height: var(--lh-sm); }
.adminmain { min-width: 0; }
@media (min-width: 900px) {
  .adminbody { display: grid; grid-template-columns: 15rem minmax(0, 1fr); gap: var(--space-6); align-items: start; }
  /* Collapsed at desktop width: a rail of icons, never nothing (feature 009). */
  .adminwrap:has(.navtoggle__input:checked) .adminbody { grid-template-columns: 3.5rem minmax(0, 1fr); }
  .adminwrap:has(.navtoggle__input:checked) .adminnav { align-items: center; }
  .adminwrap:has(.navtoggle__input:checked) .navlink { justify-content: center; gap: 0; width: 2.75rem; padding: 0; border-inline-start: 0; border-radius: var(--radius-md); }
  .adminwrap:has(.navtoggle__input:checked) .navlink > span,
  .adminwrap:has(.navtoggle__input:checked) .navgroup__label > span,
  .adminwrap:has(.navtoggle__input:checked) .navgroup__chevron { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .adminwrap:has(.navtoggle__input:checked) .navgroup { border-top-color: transparent; }
  .adminwrap:has(.navtoggle__input:checked) .navgroup:last-child { border-bottom-color: transparent; }
  .adminwrap:has(.navtoggle__input:checked) .navgroup__label { justify-content: center; padding: 0; min-height: 0; height: var(--space-4); cursor: default; }
  .adminwrap:has(.navtoggle__input:checked) .navgroup__label .icon { display: none; }
  .adminwrap:has(.navtoggle__input:checked) .navgroup > .navlink { padding-inline-start: 0; }
  /* A closed group still shows its destinations in the rail: the browser stops painting a
     closed details subtree, so the rail asks for it back. Rail mode only, so the phone
     drawer keeps ordinary group behaviour. */
  .adminwrap:has(.navtoggle__input:checked) .navgroup::details-content { content-visibility: visible; block-size: auto; }
  .navscrim { display: none; }
}
@media (max-width: 899.98px) {
  .navscrim { position: fixed; inset: 0; z-index: 60; background: var(--scrim); opacity: 0; visibility: hidden; transition: opacity 0.2s ease, visibility 0.2s ease; }
  .adminwrap:has(.navtoggle__input:checked) .navscrim { opacity: 1; visibility: visible; }
  body:has(.navtoggle__input:checked) { overflow: hidden; }
}
/* Two-mark rule below 520px: divider and suffix drop, endorsement steps down, never disappears */
@media (max-width: 519.98px) {
  .appsuffix, .appheader__sep { display: none; }
  .brandmark { height: 20px; width: 65px; }
  .appbar__inner, .appheader__right { gap: var(--space-2); }
}

/* Icon theme toggle (moon in light, sun in dark), mirrored under both triggers */
.themetoggle .ic-sun { display: none; }
[data-theme="dark"] .themetoggle .ic-moon { display: none; }
[data-theme="dark"] .themetoggle .ic-sun { display: inline-block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) .themetoggle .ic-moon { display: none; }
  :root:not([data-theme]) .themetoggle .ic-sun { display: inline-block; }
}
[data-theme="light"] .themetoggle .ic-moon { display: inline-block; }
[data-theme="light"] .themetoggle .ic-sun { display: none; }