/* Overrides on vendor/bulma.min.css: only what Bulma has no utility or
   component for. */

/* Brand palette (Headlight_ID_BrandGuide.pdf). Each value is one of the
   guide's swatches, as the HSL triple Bulma computes its light/dark/soft/
   bold/on-scheme shades from — so nothing downstream declares a colour.

   The guide's neutrals are two families and the themes take one each: Navy /
   Dark Royal / Savory Blue are one cool ramp (226deg at 36%) and become dark
   mode's ground, surfaces and borders; Bone and Rhino are the warm pair and
   become light mode's. Hence a scheme hue and saturation per theme, rather
   than one theme being a lightness flip of the other.

   The guide has no green and no amber, so success and warning stay Bulma's. */

/* Also matched on the `data-theme="light"` islands (the login card), not just
   `:root`. Bulma's own [data-theme=light] restates its entire default palette
   — teal primary, cool scheme hue, Inter — so an island would otherwise drop
   back to stock Bulma inside it. Same specificity as Bulma's rule, and this
   sheet loads second, so it wins in both places. The dark media block below
   is already written to stand down for an explicit light theme. */
:root,
[data-theme="light"] {
  /* Vermillion. Components read *-invert-l (applied at the colour's own
     hue), never the composite *-invert, so overriding that is a no-op — and
     Bulma's near-black invert is what keeps a solid vermillion button
     legible, white on #FD4641 being 3.4:1. */
  --bulma-primary-h: 2deg;
  --bulma-primary-s: 98%;
  --bulma-primary-l: 62%;
  /* Vermillion as *text* on a light ground; at full strength it is 3.3:1 on
     Bone. Bulma's own values (21%/41%) are computed for its default teal and
     are wrong both ways here — 41% is darker than the navy it would sit on. */
  --bulma-primary-on-scheme-l: 45%;

  /* Ruddy Blue's hue and saturation. Its own 74% is a light-on-dark accent
     that can't carry white text, so the fill sits at 56% and each theme sets
     its own text lightness below — dark mode's landing on Ruddy Blue exactly. */
  --bulma-link-h: 226deg;
  --bulma-link-s: 92%;
  --bulma-link-l: 56%;

  /* Crimson. It differs from the vermillion primary in saturation (59% vs
     98%), not just lightness, which is what keeps a Delete button from
     reading as a New one. Lifted from Crimson's 32% so a fill separates from
     the navy ground, and inverted to white — Bulma's computed near-black
     invert only works on its much lighter default red. The tinted form
     (`is-danger is-light`, every Revoke/Remove link) computes to a blush
     with #6B211E text, which is Crimson itself. */
  --bulma-danger-h: 2deg;
  --bulma-danger-s: 59%;
  --bulma-danger-l: 38%;
  --bulma-danger-invert-l: 100%;

  /* Powder Blue. Its dark-scheme shade computes back to Powder Blue and its
     light-scheme shade to Slate: the guide's two blues are already a pair. */
  --bulma-info-h: 196deg;
  --bulma-info-s: 66%;
  --bulma-info-l: 71%;

  /* The neutral `is-light` button (Edit, Cancel, Back) on Bone's hue. Bulma
     holds --bulma-light-l at 90% in both themes, so no per-theme value is
     needed — but it must clear the Bone page ground, hence the darker chip. */
  --bulma-light-h: 51deg;
  --bulma-light-s: 24%;

  /* Light theme: Bone ground, white cards, Rhino-family greys. Bulma derives
     the body background from --bulma-scheme-main (the cards' white); pointing
     it at Bone is what floats every bordered card on the guide's warm ground. */
  --bulma-scheme-h: 51;
  --bulma-scheme-s: 14%;
  --bulma-body-background-color: hsl(51deg, 100%, 96%);

  /* Navy ink on that warm ground — the text ramp keeps the cool hue rather
     than following the surfaces. */
  --bulma-text-h: 226deg;
  --bulma-text-s: 20%;

  /* Link text on a light ground, one step down from the solid fill. */
  --bulma-link-on-scheme-l: 50%;
}

/* Dark theme, applied twice on purpose: once for a viewer whose OS asks for
   it, once for the `data-theme="dark"` islands (navbar shell, login brand
   panel) that are dark on a light page too. Bulma's own [data-theme=dark]
   leaves scheme-h/s inherited — here Bone's warm pair — so the islands need
   the whole list, and a media query cannot cover them.

   The ladder is the guide's, not Bulma's 9/11/13/14%: Navy is the ground,
   Dark Royal the raised surfaces, borders between Dark Royal and Savory Blue.
   Text is the warm half on the cool ground, as every page of the guide sets
   it: Bone for anything strong (the logo, titles and the active nav link all
   read --bulma-text-strong), a low-saturation warm grey for body. Bone is set
   outright because the saturation making #FFFCEB a warm white at 96% makes it
   yellow at 74%. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bulma-scheme-h: 226;
    --bulma-scheme-s: 36%;

    --bulma-scheme-main-l: 11.5%; /* Navy #131828 */
    --bulma-scheme-main-bis-l: 15%;
    --bulma-scheme-main-ter-l: 18.5%; /* Dark Royal #1E2640 */
    --bulma-background-l: 18.5%;
    --bulma-border-weak-l: 24%;
    --bulma-border-l: 30%;

    /* Back to Bulma's own rule — the Bone override above is light-mode only. */
    --bulma-body-background-color: var(--bulma-scheme-main);

    --bulma-text-h: 48deg;
    --bulma-text-s: 12%;
    --bulma-text-l: 74%;
    --bulma-text-weak-l: 56%;
    --bulma-text-strong: hsl(51deg, 100%, 96%); /* Bone */
    --bulma-text-title: hsl(51deg, 100%, 96%);

    /* Ruddy Blue #7897FF, which is what 226deg/92% resolves to here. */
    --bulma-link-on-scheme-l: 73.5%;

    /* On navy, Vermillion needs no adjusting to read as text (5.1:1). */
    --bulma-primary-on-scheme-l: 62%;
  }
}

/* The same list, for the dark islands on a light page. See the media block
   above for why each value is what it is, and keep the two in step. */
[data-theme="dark"] {
  --bulma-scheme-h: 226;
  --bulma-scheme-s: 36%;

  --bulma-scheme-main-l: 11.5%; /* Navy #131828 */
  --bulma-scheme-main-bis-l: 15%;
  --bulma-scheme-main-ter-l: 18.5%; /* Dark Royal #1E2640 */
  --bulma-background-l: 18.5%;
  --bulma-border-weak-l: 24%;
  --bulma-border-l: 30%;

  /* Back to Bulma's own rule — the Bone override above is light-mode only. */
  --bulma-body-background-color: var(--bulma-scheme-main);

  --bulma-text-h: 48deg;
  --bulma-text-s: 12%;
  --bulma-text-l: 74%;
  --bulma-text-weak-l: 56%;
  --bulma-text-strong: hsl(51deg, 100%, 96%); /* Bone */
  --bulma-text-title: hsl(51deg, 100%, 96%);

  /* Ruddy Blue #7897FF, which is what 226deg/92% resolves to here. */
  --bulma-link-on-scheme-l: 73.5%;

  /* On navy, Vermillion needs no adjusting to read as text (5.1:1). */
  --bulma-primary-on-scheme-l: 62%;
}

/* Typography (Headlight_ID_BrandGuide.pdf). Gotham Book is bodycopy (400),
   Bold is headlines (700), Ultra is the super headline (800) — the 404
   numeral, the app's only display type. The weights are declared here rather
   than taken from the files: the desktop family ships each cut as its own
   family with its own usWeightClass (325/400/500), so declaring them is what
   lets one `font-family: Gotham` resolve all three, and what makes the
   font-weight 600 the pills use resolve up to Bold instead of synthesising.
   Self-hosted, no font CDN; no italics, since no template uses one. See
   vendor/gotham/README.md. */

@font-face {
  font-family: "Gotham";
  src: url("/static/vendor/gotham/gotham-book.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Gotham";
  src: url("/static/vendor/gotham/gotham-bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Gotham";
  src: url("/static/vendor/gotham/gotham-ultra.woff2") format("woff2");
  font-weight: 800;
  font-style: normal;
  font-display: swap;
}

/* Light islands too — see the palette block above. */
:root,
[data-theme="light"] {
  /* Bulma's own stack, named so the two places Gotham is not (below) can ask
     for it, and so a missing woff2 falls back to what the app used before
     rather than to a browser serif. */
  --hl-family-ui: Inter, "SF Pro", "Segoe UI", Roboto, Oxygen, Ubuntu,
    "Helvetica Neue", Helvetica, Arial, sans-serif;

  --bulma-family-primary: "Gotham", var(--hl-family-ui);
  --bulma-family-secondary: "Gotham", var(--hl-family-ui);
}

/* Bulma gives `button` font-family: inherit but leaves these three to the
   browser's own UI font. The mono exceptions set --bulma-family-code on a
   class, so they outrank this. */
input,
select,
textarea {
  font-family: inherit;
}

/* Data tables stay on the UI stack: Gotham is a display face and the
   listings are a dense 13-14px grid read by scanning. */
.data-table {
  font-family: var(--hl-family-ui);
}

/* Sticky footer: the footer (see base.html) is the last child of <body>, so
   the column lives there rather than on a wrapper div. On a page shorter
   than the viewport, .app-main's flex-grow is what keeps the footer at the
   bottom of the screen rather than floating up under the content. */
body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

.app-main {
  flex: 1 0 auto;
}

.container {
  max-width: 860px;
}

/* Navbar "shell". `data-theme="dark"` on it (see base.html) scopes Bulma's
   dark theme to just this element — that's what lets the white-only
   Headlight logo sit directly on it and stay legible no matter which theme
   the content area itself is in. */

.navbar {
  position: sticky;
  top: 0;
  z-index: 30;
}

/* The nav is flat: four links, the current section marked by a coral rule
   along the bottom edge rather than Bulma's solid block fill, which on a
   bar this dark read as a button that was stuck down. */
.navbar .app-nav-link {
  box-shadow: inset 0 -2px 0 transparent;
  transition: box-shadow 0.15s ease-in-out;
}

.navbar .app-nav-link.is-active {
  background-color: transparent;
  color: var(--bulma-text-strong);
  box-shadow: inset 0 -2px 0 var(--bulma-primary);
}

/* The account menu. The trigger is just the avatar, so it gets a ring to
   say it's pressable: faint at rest, brighter on hover and focus, coral
   while the menu is open. */
.user-menu-trigger {
  padding-left: 0.75rem;
  padding-right: 0.75rem;
}

.user-menu-trigger .user-avatar {
  box-shadow: 0 0 0 2px hsla(0, 0%, 100%, 0.12);
  transition: box-shadow 0.15s ease-in-out;
}

.user-menu-trigger:hover .user-avatar,
.user-menu-trigger:focus-visible .user-avatar {
  box-shadow: 0 0 0 2px hsla(0, 0%, 100%, 0.4);
}

.user-menu.is-active .user-menu-trigger .user-avatar {
  box-shadow: 0 0 0 2px var(--bulma-primary);
}

/* On desktop the panel is a card floating under the bar, not Bulma's flush
   sheet. The gap is padding on the (invisible) .navbar-dropdown, not margin,
   so the no-script `is-hoverable` fallback keeps an unbroken hover region;
   min-width because Bulma sizes a dropdown to its 30px trigger. The fade uses
   visibility as well as opacity, which is what keeps Log out out of the tab
   order while closed. */
@media screen and (min-width: 1024px) {
  .user-menu .navbar-dropdown {
    display: block;
    min-width: 17rem;
    padding: 0.5rem 0.25rem 0;
    background: transparent;
    border: none;
    border-radius: 0;
    box-shadow: none;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transform: translateY(-6px);
    transition:
      opacity 0.15s ease-out,
      transform 0.15s ease-out,
      visibility 0s linear 0.15s;
  }

  .user-menu.is-active .navbar-dropdown,
  .user-menu.is-hoverable:hover .navbar-dropdown,
  .user-menu.is-hoverable:focus-within .navbar-dropdown {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: translateY(0);
    transition-delay: 0s;
  }

  .user-menu-card {
    background: var(--bulma-scheme-main-ter);
    border: 1px solid var(--bulma-border);
    border-radius: 0.75rem;
    padding: 0.5rem;
    box-shadow:
      0 1px 2px hsla(var(--bulma-scheme-h), var(--bulma-scheme-s), 5%, 0.3),
      0 16px 40px -12px hsla(var(--bulma-scheme-h), var(--bulma-scheme-s), 5%, 0.6);
  }

  @media (prefers-reduced-motion: reduce) {
    .user-menu .navbar-dropdown {
      transition: none;
      transform: none;
    }
  }
}

/* Below desktop Bulma inlines the dropdown into the burger menu: the panel
   is already open and already shows the avatar, so the trigger goes. */
.user-menu-card {
  padding: 0.25rem 0.5rem;
}

@media screen and (max-width: 1023px) {
  .user-menu {
    border-top: 1px solid var(--bulma-border-weak);
    margin-top: 0.5rem;
    padding-top: 0.5rem;
  }

  .user-menu-trigger {
    display: none;
  }
}

.user-menu-identity {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 0.75rem 0.25rem;
  text-align: left;
}

.user-menu-who {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  line-height: 1.3;
  /* An email can outrun any sensible menu width; break it rather than let
     it push the card off the viewport's edge. */
  min-width: 0;
  overflow-wrap: anywhere;
}

.user-menu-name {
  font-weight: 600;
  color: var(--bulma-text-strong);
}

.user-menu-email {
  font-size: 0.8rem;
  color: var(--bulma-text-weak);
}

.user-menu-provider {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.25rem 0.75rem 0.5rem;
  font-size: 0.72rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--bulma-text-weak);
}

.user-menu .navbar-divider {
  margin: 0.25rem 0.5rem;
}

/* The card has its own padding, so the action is a rounded pill inside it
   rather than a full-bleed strip. */
.user-menu .navbar-dropdown .user-menu-action {
  padding: 0.5rem 0.75rem;
  border-radius: 0.5rem;
}

/* The primary action and a secondary menu, side by side in a page header. */
.page-header-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}

/* Bulma aligns .icon-text to flex-start against a 1.5rem line box, leaving
   a 1rem icon sitting visibly high. Global rather than scoped: every
   .icon-text in the app is an icon beside one line of text. */
.icon-text {
  align-items: center;
}

.logo-mark {
  height: 20px;
  width: auto;
  /* fill is currentColor, so it tracks whatever scheme it renders in — no
     light/dark override, and no background chip to keep it legible. */
  color: var(--bulma-text-strong);
  flex-shrink: 0;
  display: block;
}

/* Page footer (partials/version.html). Bulma's .footer is built for a fat
   marketing footer; this is a one-line strip, and it needs a border rather
   than a fill since .footer's default background is the page's own colour. */

.app-footer {
  padding: 1rem 1.5rem;
  background: transparent;
  border-top: 1px solid var(--bulma-border-weak);
  flex-shrink: 0;
}

.app-version {
  font-family: var(--bulma-family-code);
  font-size: 0.68rem;
  color: var(--bulma-text-weak);
  flex-shrink: 0;
}

/* The signed-in user's avatar (macros/avatar.html): 30px in the nav
   trigger, 40px at the head of the account panel. */
.user-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--bulma-primary-soft);
  color: var(--bulma-primary-bold);
  object-fit: cover;
  flex-shrink: 0;
  font-size: 0.75rem;
  font-weight: 700;
}

.user-avatar.is-large {
  width: 40px;
  height: 40px;
  font-size: 1rem;
}

/* Bulma caps navbar <img> at 1.75rem, which squeezes the 30px avatar into
   an oval. Both sizes are set explicitly above. */
.navbar .user-avatar {
  max-height: none;
}

/* Login: a full-bleed video hero — the client-work reel behind a navy scrim,
   with the story copy and the sign-in card over it. The one page that looks
   the same in both themes (`data-theme="dark"` on the hero, `light` on the
   card): footage can't be recoloured per scheme, and a card competing with it
   for contrast would lose.

   The rgba values below are the only ones here not from a Bulma token —
   they're washes over moving footage, not component colours, and every one is
   Navy #131828 (rgb(19 24 40)) at some alpha. A token would resolve per
   theme, which is exactly what this page must not do. */

.login-hero {
  position: relative;
  /* svh, not vh: `100vh` is mobile Safari's *expanded* viewport, so a
     full-height hero's bottom hides under the URL bar until you scroll. */
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  /* Navy under everything, so first paint is the brand ground, not white. */
  background: rgb(19 24 40);
  /* The still the two fallback paths below (no motion, small screen) show in
     the reel's place. Only a flat wash standing in for the video's
     brightness() — the scrim, vignette and grain are separate elements that
     render either way, so the two paths match without tuning gradients
     twice. Keep the alpha at 1 minus that brightness: change one and the
     still drifts brighter or darker than the footage it stands in for. */
  --login-poster:
    linear-gradient(rgb(19 24 40 / 0.56), rgb(19 24 40 / 0.56)),
    url("/static/media/login-reel-poster.jpg");
  /* Traps the reel's negative z-indices inside the hero. */
  isolation: isolate;
}

.login-reel,
.login-reel-scrim,
.login-reel-vignette,
.login-reel-grain {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.login-reel {
  z-index: -4;
  object-fit: cover;
  /* Desaturated and dimmed so the footage reads as texture rather than as
     something to watch — the card has to win. The scale hides the edge
     softening some encoders leave on the frame border. */
  filter: saturate(0.55) contrast(1.06) brightness(0.44);
  transform: scale(1.03);
}

/* Across, weighting the right where the card sits; and down, anchoring the
   top bar and the bottom edge. */
.login-reel-scrim {
  z-index: -3;
  background:
    linear-gradient(90deg, rgb(19 24 40 / 0.88) 0%, rgb(19 24 40 / 0.72) 34%, rgb(19 24 40 / 0.5) 58%, rgb(19 24 40 / 0.91) 100%),
    linear-gradient(180deg, rgb(19 24 40 / 0.84) 0%, rgb(19 24 40 / 0.34) 26%, rgb(19 24 40 / 0.42) 62%, rgb(19 24 40 / 0.89) 100%);
}

.login-reel-vignette {
  z-index: -2;
  box-shadow: inset 0 0 12vw 3vw rgb(11 14 24 / 0.7);
}

/* Static grain, inlined as an SVG turbulence filter — no request, no decode.
   `soft-light` sits it on the footage without lifting the blacks. */
.login-reel-grain {
  z-index: -1;
  opacity: 0.1;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 180 180' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
  mix-blend-mode: soft-light;
}

/* One measure for both, so the logo lines up with the headline under it. */
.login-topbar,
.login-layout {
  position: relative;
  z-index: 1;
  width: min(100% - 4rem, 1180px);
  margin-inline: auto;
}

.login-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: 5.5rem;
  flex-shrink: 0;
}

.login-logo {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
}

.login-logo .logo-mark {
  height: 22px;
}

/* A rule rather than a gap, so the label reads as a qualifier on the wordmark
   instead of a second wordmark. */
.login-logo-label {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--bulma-text-weak);
  padding-left: 0.7rem;
  border-left: 1px solid rgb(255 255 255 / 0.22);
}

/* Story copy left, card right, centred in what the top bar leaves. */
.login-layout {
  flex: 1 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 26rem);
  align-items: center;
  gap: 3rem;
  padding: 2rem 0 4rem;
}

.login-brand {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1.25rem;
  /* Wide enough that "One source of truth." holds one line at the clamp's
     ceiling — the headline is written as two lines and reads as three if it
     wraps. */
  max-width: 44rem;
  /* This column sits directly on moving footage, so it carries its own
     shadow — the scrim alone can't hold contrast against a frame that
     happens to be a white product shot. */
  text-shadow: 0 1px 24px rgb(11 14 24 / 0.75);
}

.login-kicker {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 0;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  /* Brighter than --bulma-text-weak: that lightness is tuned for a flat navy
     surface, and this sits on footage that is white in places. */
  color: rgb(255 255 255 / 0.76);
}

.login-kicker-rule {
  width: 2.5rem;
  height: 1px;
  background: var(--bulma-primary);
  flex-shrink: 0;
}

.login-headline {
  margin: 0;
  font-size: clamp(2.2rem, 4.6vw, 3.5rem);
  font-weight: 700;
  line-height: 1.04;
  letter-spacing: -0.02em;
  color: #fff;
}

/* Not italic despite the <em>: Gotham ships no italic cut, so a browser would
   synthesise a slant. Vermillion marks the emphasis instead. */
.login-headline em {
  font-style: normal;
  color: var(--bulma-primary);
}

.login-lede {
  margin: 0;
  max-width: 28rem;
  font-size: 1.05rem;
  line-height: 1.55;
  color: rgb(255 255 255 / 0.82);
}

.login-steps {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.9rem;
  margin: 0.75rem 0 0;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  /* Enough to clear 3:1 even over a frame that is white where this sits —
     the reel is 9s of other people's ad creative and some of it is. */
  color: rgb(255 255 255 / 0.62);
}

/* Separators drawn, not typed, so the steps stay three plain words in the
   DOM. */
.login-steps span + span::before {
  content: "";
  display: inline-block;
  width: 3px;
  height: 3px;
  margin-right: 0.9rem;
  border-radius: 50%;
  background: var(--bulma-primary);
  vertical-align: middle;
}

/* Not Bulma's .box: that's restyled app-wide to the flat bordered
   .table-card, and this wants the opposite — a sheet raised over the reel. */
.login-card {
  background: var(--bulma-scheme-main);
  border-radius: 1.25rem;
  box-shadow:
    0 2px 6px rgb(11 14 24 / 0.16),
    0 24px 60px rgb(11 14 24 / 0.42);
  overflow: hidden;
}

.login-card-body {
  padding: 2.5rem 2.25rem;
  display: flex;
  flex-direction: column;
}

.login-eyebrow {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  margin: 0 0 1.1rem;
  font-size: 0.65rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--bulma-text-weak);
}

.login-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--bulma-primary);
  flex-shrink: 0;
}

.login-title {
  margin: 0 0 0.35rem;
  font-size: 1.75rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--bulma-text-strong);
}

.login-subtitle {
  margin: 0 0 1.75rem;
  font-size: 0.95rem;
  line-height: 1.5;
  color: var(--bulma-text-weak);
}

/* Bordered, not filled: the official multi-colour Google mark has to sit on
   white, and a solid vermillion button would put two brands on one control. */
.login-google {
  border-color: var(--bulma-border);
  box-shadow: 0 1px 2px rgb(11 14 24 / 0.06);
}

.google-mark {
  width: 18px;
  height: 18px;
}

.login-error,
.login-note {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
}

.login-error {
  padding: 0.75rem 1rem;
  font-size: 0.85rem;
}

.login-note {
  margin-top: 1.1rem;
  align-items: center;
}

/* Under the breakpoint the columns stack and the reel becomes its own poster:
   2.8MB of autoplaying video is the wrong thing to hand a phone, and `cover`
   on a portrait viewport crops a 16:9 frame to a strip of itself anyway. The
   150KB poster crops the same way. */
@media (max-width: 900px) {
  .login-hero {
    background-image: var(--login-poster);
    background-size: cover;
    background-position: center;
  }

  .login-reel {
    display: none;
  }

  .login-topbar,
  .login-layout {
    width: min(100% - 2.5rem, 30rem);
  }

  .login-layout {
    grid-template-columns: minmax(0, 1fr);
    gap: 2.25rem;
    padding: 1rem 0 3rem;
  }

  .login-headline {
    font-size: clamp(2rem, 9vw, 2.75rem);
  }

  .login-card-body {
    padding: 2rem 1.5rem;
  }
}

/* A looping video is exactly the motion this query is for. Only the video is
   dropped, not the layout — the stacking above is a bandwidth decision and
   this one isn't. */
@media (prefers-reduced-motion: reduce) {
  .login-hero {
    background-image: var(--login-poster);
    background-size: cover;
    background-position: center;
  }

  .login-reel {
    display: none;
  }
}

/* Clients listing and detail page: the page header, table card, entity
   cell, resource links and key/value grid Bulma has no component for. */

.page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1.5rem;
}

/* The title block gives way first, wrapping its subtitle, so the action
   beside it stays on the same line until the page is genuinely too narrow. */
.page-header > :first-child {
  flex: 1 1 16rem;
  min-width: 0;
}

/* The Active/Inactive switch: Bulma's toggle tabs, with the count riding
   inside each segment. Tinted from currentColor so the pill reads the same
   on the selected segment (light on the link fill) as on the other. */
.status-tabs {
  margin-bottom: 1.25rem;
}

.status-tabs a {
  gap: 0.4rem;
}

.count-pill {
  display: inline-block;
  min-width: 1.7em;
  padding: 0 0.5em;
  border-radius: 999px;
  background: color-mix(in srgb, currentColor 14%, transparent);
  font-size: 0.72rem;
  font-weight: 600;
  line-height: 1.6;
  text-align: center;
  vertical-align: middle;
}

/* Every card is the same bordered, rounded panel: .box (forms), .table-card
   (listings), .detail-card. Bulma's .box is restyled rather than replaced —
   the form tests count its boxes. */
.box {
  --bulma-box-shadow: none;
  --bulma-box-radius: var(--bulma-radius-large);
  border: 1px solid var(--bulma-border-weak);
}

/* A table in a bordered, rounded card rather than a shadowed box. Scrolls
   sideways on a narrow screen rather than pushing the page wider. */
.table-card {
  border: 1px solid var(--bulma-border-weak);
  border-radius: var(--bulma-radius-large);
  background: var(--bulma-scheme-main);
  overflow-x: auto;
}

.data-table thead th {
  padding: 0.7rem 1rem;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--bulma-text-weak);
  background: var(--bulma-scheme-main-bis);
  border-bottom-width: 1px;
  white-space: nowrap;
}

.data-table tbody td {
  padding: 0.85rem 1rem;
  vertical-align: middle;
}

.data-table tbody tr:last-child td {
  border-bottom: 0;
}

/* The first cell of every listing: icon tile, name, and one line under it,
   so one column reads as one thing. The min-width stops a phone-width table
   squeezing the name to a letter per line — the card scrolls instead. */
.entity-cell {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-width: 13rem;
}

.entity-text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  min-width: 0;
}

/* A short free-text cell — what a service account is for — sits between the
   tiny secondary lines and the body copy, so a sentence reads as part of
   the row rather than as a paragraph dropped into it. */
.data-table .cell-text {
  font-size: 0.9rem;
  line-height: 1.4;
}

.entity-name {
  font-weight: 600;
  color: var(--bulma-text-strong);
  overflow-wrap: break-word;
}

a.entity-name:hover {
  color: var(--bulma-link);
}

.entity-sub {
  font-size: 0.78rem;
  color: var(--bulma-text-weak);
  overflow-wrap: anywhere;
}

.is-mono {
  font-family: var(--bulma-family-code);
}

.entity-sub.is-mono {
  font-size: 0.72rem;
}

/* A secondary line that must not break mid-word — "by someone@…" under a
   date: the column beside it gives way instead. */
.entity-sub.is-nowrap {
  white-space: nowrap;
}

.entity-name.is-mono {
  font-size: 0.85rem;
}

/* The tile an entity's icon sits in. The favicon macro renders its own
   fixed 16px icon; this just frames it. `is-large` is the detail header. */
.entity-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: var(--bulma-radius);
  border: 1px solid var(--bulma-border-weak);
  background: var(--bulma-scheme-main-bis);
  color: var(--bulma-text-weak);
  flex: none;
}

.entity-avatar.is-large {
  width: 48px;
  height: 48px;
  border-radius: var(--bulma-radius-large);
}

.entity-avatar.is-large .client-favicon {
  width: 28px;
  height: 28px;
  font-size: 1.35rem;
}

/* An expired token's row: still listed, visibly past. */
.data-table tr.is-muted td {
  opacity: 0.55;
}

/* Edit/Remove side by side in a listing's last cell. Bulma's .buttons adds
   a bottom margin for the row it expects to sit above. */
.row-actions {
  flex-wrap: nowrap;
}

.row-actions,
.row-actions .button {
  margin-bottom: 0;
}

/* The three per-client links share one wrapping cell: a column apiece was
   wider than the container at the lengths repo and bucket names run to. */
.resource-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 1.25rem;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.85rem;
  min-width: 14rem;
}

.resource-links .icon-text {
  overflow-wrap: break-word;
}

.timestamp {
  font-size: 0.8rem;
  color: var(--bulma-text-weak);
  white-space: nowrap;
}

/* Empty states: a dashed frame says "nothing here yet" without the weight
   of a filled box. */
.empty-state {
  padding: 3rem 1.5rem;
  border: 1px dashed var(--bulma-border);
  border-radius: var(--bulma-radius-large);
  text-align: center;
}

.empty-state-icon {
  color: var(--bulma-text-weak);
  margin-bottom: 0.5rem;
}

/* A titled block above a table card's rows — the sync/favicon result pages'
   per-outcome groups. */
.table-card-head {
  padding: 1rem 1rem 0.75rem;
  border-bottom: 1px solid var(--bulma-border-weak);
}

.outcome-slug {
  width: 30%;
}

/* The result pages' outcome counts: one tile per outcome kind. */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
  gap: 0.75rem;
  margin-bottom: 1.25rem;
}

.stat-tile {
  border: 1px solid var(--bulma-border-weak);
  border-radius: var(--bulma-radius-large);
  background: var(--bulma-scheme-main);
  padding: 1rem 0.75rem;
  text-align: center;
}

.stat-value {
  font-size: 1.6rem;
  font-weight: 700;
  line-height: 1.2;
  color: var(--bulma-text-strong);
}

.stat-label {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--bulma-text-weak);
}

/* "What will happen" on the sync and favicon confirmations: each step is
   an icon tile beside a title and a line of explanation. */
.step-list {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.step-list > li {
  display: flex;
  gap: 0.85rem;
  align-items: flex-start;
}

.step-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: var(--bulma-radius);
  border: 1px solid var(--bulma-border-weak);
  background: var(--bulma-scheme-main-bis);
  flex: none;
}

/* Overview page. The attention list is the sync confirmation's step list
   with a tone per item and an action on the right; the two-column band
   below the tiles stacks on narrow screens. */
.attention-list {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.attention-item {
  display: flex;
  align-items: flex-start;
  gap: 0.85rem;
  padding-bottom: 0.85rem;
  border-bottom: 1px solid var(--bulma-border-weak);
}

.attention-item:last-child {
  padding-bottom: 0;
  border-bottom: 0;
}

.attention-body {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 0.9rem;
}

/* soft/bold, like the status pills and section icon: only those swap
   lightness with the theme, so a tone stays a tint of the ground rather than
   a pale disc on the navy one. */
.attention-icon.is-danger {
  color: var(--bulma-danger-bold);
  background: var(--bulma-danger-soft);
  border-color: transparent;
}

.attention-icon.is-warning {
  color: var(--bulma-warning-bold);
  background: var(--bulma-warning-soft);
  border-color: transparent;
}

.attention-icon.is-info {
  color: var(--bulma-info-bold);
  background: var(--bulma-info-soft);
  border-color: transparent;
}

.attention-action {
  flex: none;
  margin-bottom: 0;
}

.attention-clear {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--bulma-text-weak);
}

a.stat-tile {
  display: block;
  color: inherit;
}

a.stat-tile:hover {
  border-color: var(--bulma-link);
}

.stat-of {
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--bulma-text-weak);
}

.stat-detail {
  margin-top: 0.25rem;
  font-size: 0.72rem;
  color: var(--bulma-text-weak);
}

.overview-columns {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
  gap: 1.25rem;
  align-items: start;
}

.overview-columns > .table-card,
.overview-columns > .detail-card {
  margin-bottom: 0;
}

.detail-grid-compact .detail-row {
  grid-template-columns: 9rem 1fr;
  padding: 0.55rem 0;
}

.detail-grid-compact .detail-value {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 0.6rem;
}

/* Detail page: a header card (identity, actions, where the client's things
   live), then one card per section. */

.detail-card {
  border: 1px solid var(--bulma-border-weak);
  border-radius: var(--bulma-radius-large);
  background: var(--bulma-scheme-main);
  padding: 1.25rem 1.5rem;
  margin-bottom: 1.25rem;
}

.detail-card-title {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--bulma-text-weak);
}

.detail-header {
  padding: 0;
}

.detail-identity {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  padding: 1.5rem;
}

.detail-identity-text {
  flex: 1 1 12rem;
  min-width: 0;
}

.detail-identity-text .title {
  overflow-wrap: anywhere;
}

.detail-meta {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
}

.detail-meta .entity-sub {
  font-size: 0.8rem;
}

/* Bulma's .buttons adds a bottom margin for the row it expects to sit
   above; here the buttons are the row's last item. */
.detail-actions {
  margin-bottom: 0;
  flex: none;
}

.detail-actions .button:last-child {
  margin-bottom: 0;
}

/* The client's status beside its slug. soft/bold, not light/light-invert:
   only soft/bold swap with the theme (90/20 becomes 20/90), so the pill sits
   in the navy ground rather than glowing on it. */
.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.1rem 0.6rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 600;
}

.status-pill.is-success {
  background: var(--bulma-success-soft);
  color: var(--bulma-success-bold);
}

.status-pill.is-warning {
  background: var(--bulma-warning-soft);
  color: var(--bulma-warning-bold);
}

.status-pill.is-danger {
  background: var(--bulma-danger-soft);
  color: var(--bulma-danger-bold);
}

/* Three labelled links, side by side while they fit. Flex from each item's
   own width rather than equal columns, so the dbt breadcrumb — the longest —
   takes what it needs before the others split the rest. */
.detail-facts {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 2rem;
  padding: 1rem 1.5rem 1.25rem;
  border-top: 1px solid var(--bulma-border-weak);
  background: var(--bulma-scheme-main-bis);
  border-radius: 0 0 var(--bulma-radius-large) var(--bulma-radius-large);
  margin: 0;
}

.detail-fact {
  flex: 1 1 auto;
  min-width: 11rem;
}

.detail-fact dt {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--bulma-text-weak);
  margin-bottom: 0.25rem;
}

.detail-fact dd {
  font-size: 0.9rem;
  margin: 0;
  overflow-wrap: anywhere;
}

/* The key/value grid. Bulma has no component for this. */

.detail-grid {
  display: flex;
  flex-direction: column;
  margin: 0;
}

.detail-row {
  display: grid;
  grid-template-columns: 180px 1fr;
  gap: 1rem;
  padding: 0.75rem 0;
  border-bottom: 1px solid var(--bulma-border-weak);
}

.detail-row:first-child {
  padding-top: 0;
}

.detail-row:last-child {
  border-bottom: none;
  padding-bottom: 0;
}

.detail-label {
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--bulma-text-weak);
  padding-top: 0.1rem;
}

.detail-value {
  font-size: 0.92rem;
  min-width: 0;
  margin: 0;
  overflow-wrap: anywhere;
}

/* A long free-text value (notes) keeps the line breaks it was typed with. */
.prose-value {
  white-space: pre-wrap;
}

/* A nested optional model inside a table cell — an account's attrs — as a
   compact run of `label value` pairs rather than a second table. */
.inline-facts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1rem;
  margin: 0;
  font-size: 0.85rem;
}

.inline-fact {
  display: flex;
  gap: 0.35rem;
  align-items: baseline;
}

.inline-fact dt {
  color: var(--bulma-text-weak);
  font-size: 0.75rem;
}

.inline-fact dd {
  margin: 0;
}

.detail-empty {
  font-size: 0.9rem;
}

.json-preview {
  background: var(--bulma-scheme-main-bis);
  border: 1px solid var(--bulma-border-weak);
  border-radius: var(--bulma-radius-small);
  padding: 0.75rem 0.9rem;
  font-size: 0.82rem;
  font-family: var(--bulma-family-code);
  overflow-x: auto;
  margin: 0;
}

.back-link {
  margin-top: 0.5rem;
  display: inline-block;
  font-size: 0.9rem;
}

/* Forms: checkbox groups, toggle switches, nested optional-model fieldsets.
   The fieldset stays a real <fieldset> — native `disabled` is what excludes
   its fields from submission when the toggle is off (see dynamic_form.js). */

.checkbox-group {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.1rem;
}

.checkbox-group-option {
  font-weight: 400;
}

/* A list[str] field (`tags`) as a token input. The container carries Bulma's
   `.input`, so border, hover and the focus ring are the same tokens as every
   other field (Bulma 1 styles `.input:focus-within`); only what a single-line
   input assumes is overridden — it wraps and grows. See
   macros/form_fields.html's render_string_list_control. */

.tag-field {
  height: auto;
  min-height: var(--bulma-control-height);
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem 0.4rem;
  padding-top: 0.3em;
  padding-bottom: 0.3em;
  cursor: text;
}

.tag-field .tag-chip {
  margin: 0;
  cursor: default;
  max-width: 100%;
}

.tag-field .tag-chip [data-tag-text] {
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Without the script, the checkbox is how a chip is removed, so it shows.
   Once the script is running, the x button does that job and the checkbox
   is only the value carrier. */
.tag-field .tag-chip input[type="checkbox"] {
  margin: 0 0.4em 0 0;
}

.tag-field.is-enhanced .tag-chip input[type="checkbox"] {
  display: none;
}

.tag-field .tag-chip .delete {
  margin-left: 0.4em;
  margin-right: -0.25em;
}

.tag-field-input {
  flex: 1 1 8ch;
  min-width: 8ch;
  appearance: none;
  border: none;
  background: transparent;
  box-shadow: none;
  outline: none;
  padding: 0;
  margin: 0;
  height: auto;
  font: inherit;
  color: inherit;
}

.tag-field-input::placeholder {
  color: var(--bulma-input-placeholder-color);
}

/* A boolean scalar as a toggle switch: Bulma core has no switch component,
   so this is a real <input type="checkbox"> with only its appearance hidden
   — still keyboard-focusable and label-associated — and the track paints
   from its sibling :checked state, so no JS is involved. */

.toggle-switch {
  position: relative;
  display: inline-block;
  width: 2.5rem;
  height: 1.4rem;
  vertical-align: middle;
  cursor: pointer;
  flex-shrink: 0;
}

.toggle-switch input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.toggle-switch-track {
  position: absolute;
  inset: 0;
  background: var(--bulma-border);
  border-radius: 999px;
  transition: background-color 0.15s ease-in-out;
}

.toggle-switch-track::before {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: calc(1.4rem - 4px);
  height: calc(1.4rem - 4px);
  border-radius: 50%;
  background: var(--bulma-scheme-main);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
  transition: transform 0.15s ease-in-out;
}

.toggle-switch input:checked + .toggle-switch-track {
  background: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-l));
}

.toggle-switch input:checked + .toggle-switch-track::before {
  transform: translateX(calc(2.5rem - 1.4rem));
}

.toggle-switch input:focus-visible + .toggle-switch-track {
  outline: 2px solid hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-l));
  outline-offset: 2px;
}

.toggle-switch input:disabled + .toggle-switch-track {
  opacity: 0.5;
  cursor: not-allowed;
}

textarea.json-field {
  font-family: var(--bulma-family-code);
  font-size: 0.85rem;
}

input[type="checkbox"] {
  accent-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-l));
}

fieldset.model-field,
fieldset.model-list-field,
fieldset.model-list-row {
  border: 1px solid var(--bulma-border-weak);
  border-radius: var(--bulma-radius);
  padding: 1.1rem 1.2rem 1.2rem;
  margin: 0 0 1.2rem;
  min-width: 0;
  background: var(--bulma-scheme-main-bis);
}

fieldset.model-field legend,
fieldset.model-list-field legend {
  padding: 0 0.45rem;
  font-weight: 600;
  font-size: 0.88rem;
  color: var(--bulma-text-strong);
}

.model-toggle {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-weight: 600;
  font-size: 0.88rem;
  cursor: pointer;
}

fieldset.model-field:disabled {
  opacity: 0.55;
}

fieldset.model-field:disabled .field,
fieldset.model-field:disabled fieldset {
  cursor: not-allowed;
}

fieldset.model-field > .help,
fieldset.model-list-field > .help {
  margin-top: -0.45rem;
}

/* A repeatable row: its scalar fields share a grid so channel, account id
   and the enabled switch sit across one line where there's room, while the
   header line (holding Remove) and any nested sub-model span the full
   width. */
fieldset.model-list-row {
  background: var(--bulma-scheme-main);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  column-gap: 1.25rem;
  padding-top: 0.85rem;
}

.model-list-row-head,
fieldset.model-list-row > fieldset.model-field,
fieldset.model-list-row > .help {
  grid-column: 1 / -1;
}

.model-list-row-head {
  display: flex;
  justify-content: flex-end;
  margin-bottom: 0.5rem;
}

.model-list-row-head .button {
  margin-bottom: 0;
}

/* A list filling a whole tab is already named by that tab, so it sheds its
   frame and legend. Scoped to `.has-form-tabs`, which form_tabs.js sets only
   once the bar is on screen — until then the tab doing the naming is
   display:none and the section needs its legend back. */
.has-form-tabs fieldset.model-list-field.is-bare {
  border: 0;
  border-radius: 0;
  background: none;
  padding: 0;
  margin: 0;
}

.has-form-tabs fieldset.model-list-field.is-bare > legend {
  display: none;
}

.has-form-tabs fieldset.model-list-field.is-bare > .help {
  margin-top: 0;
}

/* One visible level of nesting instead of three: inside a repeatable row,
   an optional sub-model is an indented block with a rule down its side
   rather than yet another filled, bordered box. */
fieldset.model-list-row > fieldset.model-field {
  border: 0;
  border-left: 2px solid var(--bulma-border-weak);
  border-radius: 0;
  background: none;
  padding: 0.15rem 0 0 0.9rem;
}

/* The tuck below is for a legend sitting in a border. This one has no
   border to sit in, so its help text needs the room back. */
fieldset.model-list-row > fieldset.model-field > .help {
  margin-top: 0.15rem;
}

/* Tabs on the client form. This restates the `hidden` attribute the bar
   renders with, because Bulma gives `.tabs` a `display: flex` that would
   otherwise beat the browser's own [hidden] rule. Nothing here hides anything
   on its own: without the script the bar stays hidden and every pane visible,
   leaving a script-less browser the plain stacked form. */
.form-tabs[hidden],
.tab-pane[hidden] {
  display: none;
}

.form-tabs {
  margin-bottom: 1.25rem;
}

.form-tabs a {
  gap: 0.4rem;
}

/* A tab holding validation errors wears its count in solid danger, so it
   stands out from the neutral counts on the listing's status switch. */
.count-pill.is-danger {
  background: var(--bulma-danger);
  color: var(--bulma-danger-invert);
}

/* The save sits outside the form's boxes, on the page itself, to say that
   it commits everything in them rather than whichever tab is open. It needs
   no rule above it to separate it -- the gap below the last box does
   that. */
.form-actions {
  margin-top: 1.5rem;
}

/* Below Bulma's navbar breakpoint (1024px, default) navbar-menu — the nav
   link plus user chip and logout — collapses behind the burger already;
   this is just to keep the always-visible brand row from crowding the
   burger on narrow phones. */
@media (max-width: 400px) {
  .brand-name {
    display: none;
  }
}

@media (max-width: 560px) {
  .detail-row {
    grid-template-columns: 1fr;
    gap: 0.25rem;
  }

  .detail-identity,
  .detail-facts {
    padding-left: 1rem;
    padding-right: 1rem;
  }

  .detail-card {
    padding: 1rem;
  }
}

/* The access page: one section per credential, its header standing above a
   card that holds only the entries. Inside the card, beside rows built from
   the same icon-tile-and-two-lines cell, the header read as one more row.
   Two sections means two primary buttons, each in its own header rather than
   the page's, so each plainly belongs to its list. */
.access-section {
  margin-bottom: 2.5rem;
  scroll-margin-top: 1.25rem;
}

.access-section:last-child {
  margin-bottom: 0;
}

.section-header {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 0.9rem;
}

/* The icon disc — the one coloured mark on the page apart from the buttons.
   soft/bold for the same reason the status pills are. */
.section-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: var(--bulma-radius-large);
  background: var(--bulma-primary-soft);
  color: var(--bulma-primary-bold);
  font-size: 1.15rem;
  flex: none;
}

.section-header-text {
  flex: 1 1 16rem;
  min-width: 0;
}

.section-title {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-size: 1.3rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--bulma-text-strong);
  line-height: 1.25;
}

.section-title .count-pill {
  font-size: 0.75rem;
  color: var(--bulma-text-weak);
}

.section-desc {
  margin-top: 0.2rem;
  font-size: 0.9rem;
  color: var(--bulma-text-weak);
}

/* A notice inside a card, above its rows. */
.section-strip {
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--bulma-border-weak);
}

.section-strip .notification {
  margin-bottom: 0;
}

/* An empty state sitting inside a card (below the audience strip, say)
   keeps its dashed frame — that frame is how every listing says "nothing
   here" — inset from the card's edge. */
.empty-state.is-inset {
  margin: 1rem;
  padding: 2rem 1.5rem;
}

/* Arriving by anchor — from the overview's attention items, or the old
   listing URLs — lights the card up for a moment so the eye lands on the
   right list rather than hunting down the page. */
.access-section:target .table-card {
  animation: target-ring 1.8s ease-out;
}

@keyframes target-ring {
  0%,
  35% {
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--bulma-link) 45%, transparent);
  }
  100% {
    box-shadow: 0 0 0 3px transparent;
  }
}

@media (prefers-reduced-motion: reduce) {
  .access-section:target .table-card {
    animation: none;
  }
}

/* The audience callout: a plain <details>, so it works with no JavaScript,
   and Bulma styles neither element, so this is the whole of it. */
.audience-card {
  border: 1px solid var(--bulma-border-weak);
  border-radius: var(--bulma-radius-large);
  background: var(--bulma-scheme-main);
  margin-bottom: 1.25rem;
}

.audience-card > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  padding: 0.85rem 1.25rem;
  cursor: pointer;
  list-style: none;
}

.audience-card > summary::-webkit-details-marker {
  display: none;
}

/* A focused summary is keyboard navigation, not a click. */
.audience-card > summary:focus-visible {
  outline: 2px solid var(--bulma-link);
  outline-offset: 2px;
  border-radius: var(--bulma-radius-large);
}

.audience-summary {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  min-width: 0;
}

.audience-label {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--bulma-text-weak);
}

.audience-value {
  overflow-wrap: anywhere;
}

.audience-hint {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.8rem;
  color: var(--bulma-link);
  white-space: nowrap;
}

.audience-hint .icon {
  transition: transform 0.15s ease-in-out;
}

.audience-card[open] .audience-hint .icon {
  transform: rotate(180deg);
}

.audience-body {
  padding: 0 1.25rem 1.25rem;
  border-top: 1px solid var(--bulma-border-weak);
  padding-top: 1rem;
  font-size: 0.9rem;
}

.audience-body pre {
  background-color: var(--bulma-scheme-main-bis);
  border: 1px solid var(--bulma-border-weak);
  border-radius: var(--bulma-radius-small);
}

/* Inside the service-accounts card on the access page the same <details> is
   a strip between the head and the rows — tinted, with a rule below it —
   rather than a card floating on its own. */
.audience-card.is-embedded {
  border: 0;
  border-bottom: 1px solid var(--bulma-border-weak);
  border-radius: 0;
  background: var(--bulma-scheme-main-bis);
  margin-bottom: 0;
}

.audience-card.is-embedded > summary:focus-visible {
  outline-offset: -2px;
  border-radius: 0;
}

/* A client's cached favicon and the fallback that stands in without one.
   Both pinned to the same 16px box: stored dimensions vary per client
   (Google's service caps rather than resizes), and without a fixed box the
   name column would shift as icons come and go. `flex: none` because the
   cell is a flex row — without it a narrow viewport squeezes the icon
   instead of wrapping the name. */
.client-favicon {
  width: 16px;
  height: 16px;
  flex: none;
}

/* The image itself keeps its aspect ratio inside that box rather than being
   stretched to fill it — a non-square source (a JPEG icon, say) would
   otherwise render distorted. */
img.client-favicon {
  object-fit: contain;
}

.client-favicon-fallback {
  color: var(--bulma-text-weak);
}

/* The not-found page: a two-column hero, on the page rather than in a card.
   The "404" is a gradient of the two brand colours — Vermillion flat, since
   display type owes only 3:1, running into --bulma-link-text rather than the
   flat link fill, whose lightness is picked to carry white text and dims to
   3.2:1 on navy; that token is per-theme, so the tail lands on Ruddy Blue in
   dark and a deep royal in light. The art is a transparent PNG and the glow
   behind it a blurred radial gradient on Bone's hue, so both read on either
   theme. Below tablet width the columns stack, art first. */
.not-found {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  gap: 2rem 3rem;
  align-items: center;
  min-height: 60vh;
  padding: 1.5rem 0 3rem;
}

.not-found-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  /* -on-scheme, not the flat --bulma-primary the "404" below uses: this is
     0.75rem bold, so it owes 4.5:1 rather than display type's 3:1. */
  color: var(--bulma-primary-on-scheme);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.not-found-code {
  margin: 0.25rem 0 0.75rem;
  font-size: clamp(5.5rem, 15vw, 8.5rem);
  font-weight: 800;
  line-height: 0.9;
  letter-spacing: -0.05em;
  background: linear-gradient(110deg, var(--bulma-primary) 10%, var(--bulma-link-text) 95%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.not-found-title {
  margin-bottom: 0.75rem;
  color: var(--bulma-text-strong);
  font-size: 1.75rem;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.01em;
}

.not-found-lede {
  color: var(--bulma-text);
  font-size: 1.05rem;
  line-height: 1.65;
}

/* A long or garbage URL must wrap rather than widen the page — at a slash
   if it can, mid-word only when a single segment is wider than the column. */
.not-found-path {
  overflow-wrap: anywhere;
}

.not-found-figure {
  position: relative;
}

.not-found-figure::before {
  content: "";
  position: absolute;
  inset: 8% 4%;
  border-radius: 50%;
  background: radial-gradient(closest-side, hsla(51, 100%, 62%, 0.4), transparent);
  filter: blur(28px);
}

.not-found-art {
  position: relative;
  display: block;
  width: 100%;
  height: auto;
}

/* `minmax(0, 1fr)` rather than `1fr`: the latter is `minmax(auto, 1fr)`,
   whose minimum is the copy's min-content width, and a long path would push
   the whole column past the viewport. */
@media screen and (max-width: 768px) {
  .not-found {
    grid-template-columns: minmax(0, 1fr);
    gap: 1rem;
    min-height: auto;
    text-align: center;
  }

  .not-found-figure {
    order: -1;
    max-width: 18rem;
    margin: 0 auto;
  }

  .not-found-eyebrow {
    justify-content: center;
  }
}
