/* Workspace layout. Uses the existing tokens and module registry.
   Loaded after the canvas, for both Hank and the rental app. */
.hb-rail {
  background: linear-gradient(180deg, var(--surface) 65%, var(--violet-soft));
  border-right: 1px solid var(--border);
  gap: var(--space-3);
}
.hb-rail-mark { box-shadow: none; border-color: var(--border); margin-bottom: 0; }
/* ── THE RAIL HEAD IS THE LOCKUP ────────────────────────────────────────────
   The full brand puts both marks in the DOM — the lockup and the short mark —
   and harris.css picks between them by VIEWPORT. This rail does not follow the
   viewport: it is a 68px column from 769px all the way to 1099px, and the
   lockup dropped into that is a lockup four times the width of its container.
   So the column takes the short mark at every width, and the rule that opens
   the rail out is the one that asks for the lockup back. */
.hb-rail .hb-rail-mark img.hb-logo-full { display: none; }
.hb-rail .hb-rail-mark img.hb-logo-compact { display: block; }
/* ONLY WHERE THERE IS NOTHING UPLOADED. The text pair is the fallback, and an
   unguarded rule for it put the letter tile ABOVE the uploaded mark — the same
   two-marks-at-once fault harris.css records in its own comment, found by
   rendering the column rather than by reading the cascade. */
.hb-rail .hb-rail-mark:not(:has(img.hb-logo)) .hb-wordmark:not(.hb-wordmark-compact) { display: none; }
.hb-rail .hb-rail-mark:not(:has(img.hb-logo)) .hb-wordmark-compact { display: inline-flex; }
.hb-rail-label { display: none; }
.hb-rail-home { display: flex; flex-direction: column; gap: var(--space-1); }
.hb-workspace-link {
  display: flex; align-items: center; justify-content: center; gap: var(--space-3);
  width: 40px; min-height: 40px; border-radius: var(--radius-3);
  text-decoration: none; color: var(--ink-2); font-size: var(--t-body); font-weight: var(--w-medium);
}
.hb-workspace-link svg { width: 19px; height: 19px; flex: none; }
.hb-workspace-link span { display: none; }
.hb-workspace-link:hover { background: var(--surface-2); color: var(--ink); }
.hb-workspace-link.here { background: var(--blue-soft); color: var(--blue-ink); }
.hb-workspace-link:focus-visible { outline: 2px solid var(--blue-ink); outline-offset: 2px; }
.hb-rail-links { border-top: 1px solid var(--border); padding-top: var(--space-3); }
.hb-rail a.hb-rl { color: var(--ink-2); }
.hb-rail a.hb-rl.here { color: var(--ink); box-shadow: none; }
.hb-rail a.hb-rl svg { flex: none; color: var(--rl-ink, var(--ink-2)); }
.hb-rail-foot { width: 100%; padding-top: var(--space-3); border-top: 1px solid var(--border); }
.hb-rail-account { display: flex; align-items: center; justify-content: center; gap: var(--space-3); min-width: 0; }
.hb-account-label { display: none; min-width: 0; flex-direction: column; gap: 1px; font-size: var(--t-small); color: var(--ink-2); }
/* The word is what shows until the rail is told who this is, and it stays the
   answer wherever an address cannot be read. */
.hb-account-name, .hb-account-mail { display: none; max-width: 100%; overflow: hidden; }
/* THE NAME WRAPS, THE ADDRESS DOES NOT. Half a name is a different person —
   "Maddison Fitzgeral…" — and a name is short words that break cleanly, so it
   takes a second line and stops at two. An address cannot break usefully at
   this width, so it is cut, and the title and the menu both hold it whole. */
.hb-account-name {
  font-weight: var(--w-medium); color: var(--ink); line-height: 1.25;
  -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.hb-account-mail {
  font-size: var(--t-micro); color: var(--ink-3); line-height: 1.25;
  white-space: nowrap; text-overflow: ellipsis;
}
.hb-rail-me { width: 40px; height: 40px; flex: none; }
.hb-room { padding-right: 0; padding-bottom: 100px; }
body.hb-canvas:not(:has(.sidebar)) .hb-room > .wrap { padding-block: var(--space-6); }
.hb-room .page-h { margin-bottom: var(--space-5); }
.hb-room .page-h h1 { font-size: var(--t-hero); letter-spacing: -.035em; line-height: 1.2; }
.hb-room .page-h h1 .hb-module-mark { width: 40px !important; height: 40px !important; }
.hb-room .page-h .lede { font-size: var(--t-title); max-width: 640px; line-height: 1.65; }
.hb-room .page-h-row { padding-right: 0; }
.hb-room .viewbar { margin-bottom: var(--space-5); }
.hb-room .viewbar-inner { background: var(--surface); border-color: var(--border); border-radius: var(--radius-3); }
.hb-room .viewbar a { border-radius: 6px; }
.hb-room .btn { border-radius: var(--radius-3); font-weight: var(--w-medium); }
.hb-room .btn-primary { box-shadow: 0 1px 2px rgba(21,23,26,.12); }
.hb-room :is(.card, .panel) { border-radius: var(--radius-2); box-shadow: var(--shadow-sm); }
.hb-room :is(.hm-card, .rv-stat) { font-variant-numeric: tabular-nums; }
.hb-room .hm-card { padding: var(--space-4); }
.hb-room .mc-value { letter-spacing: -.035em; }
.hb-ai { box-shadow: var(--shadow-md); border: 1px solid var(--ai-border); }
.hb-ai-orb { width: 24px; height: 24px; }
.hb-eyebrow {
  display: block; margin-bottom: var(--space-3); font-size: var(--t-small);
  font-weight: var(--w-medium); letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3);
}

/* Readable labels on a full desktop; compact rail on smaller laptops/tablets. */
@media (min-width: 1100px) {
  .hb-canvas, .hb-railed { --hb-rail-w: 216px; }
  .hb-rail { width: var(--hb-rail-w); align-items: stretch; padding: var(--space-5) var(--space-3); }
  /* Open enough for the real lockup, so the tile goes: a wordmark in a rounded
     box with a border round it is a mark wearing an icon's clothes. The height
     is the box, and the artwork is about two thirds of it, so 44 draws a mark
     about the size of the heading it replaces. */
  .hb-rail-mark {
    align-self: flex-start; margin-left: var(--space-2);
    --hb-logo-h: 44px;
    width: auto; height: auto; max-width: calc(100% - var(--space-2));
    justify-items: start;
    background: none; border: 0; border-radius: 0;
  }
  .hb-rail .hb-rail-mark img.hb-logo-full { display: block; }
  .hb-rail .hb-rail-mark img.hb-logo-compact { display: none; }
  /* Carrying the same :not(:has(…)) as the rule above, because a guard also
     carries specificity: without it the narrow rail's letter tile outranked
     this and an un-branded site got the tile in a 216px rail with room for the
     name. Found by driving the site with nothing uploaded. */
  .hb-rail .hb-rail-mark:not(:has(img.hb-logo)) .hb-wordmark:not(.hb-wordmark-compact) { display: inline-flex; }
  .hb-rail .hb-rail-mark:not(:has(img.hb-logo)) .hb-wordmark-compact { display: none; }
  .hb-rail-home { margin-top: var(--space-4); }
  .hb-workspace-link, .hb-rail a.hb-rl {
    width: 100%; min-height: 40px; height: auto; display: flex; justify-content: flex-start;
    padding: var(--space-2) var(--space-3); gap: var(--space-3); border-radius: var(--radius-3);
  }
  .hb-workspace-link span { display: block; }
  .hb-rail-links { align-items: stretch; }
  .hb-rail-label { display: block; min-width: 0; font-size: var(--t-small); font-weight: var(--w-medium); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .hb-rail-foot { flex-direction: row; justify-content: flex-start; padding-inline: var(--space-2); }
  .hb-rail-account { justify-content: flex-start; flex: 1; }
  .hb-account-label { display: flex; flex: 1; }
  /* Only once the rail has been told. Until then the word stays, so the foot
     is never a blank line beside a blank circle. */
  .hb-rail.hb-knows-me .hb-account-word { display: none; }
  .hb-rail.hb-knows-me .hb-account-name { display: -webkit-box; }
  .hb-rail.hb-knows-me .hb-account-mail { display: block; }
}

/* The application catalog: scan destinations without reading tall tiles. */
.hb-catalog .hb-rail-links { display: none; }
.hb-catalog .page-h {
  position: relative; isolation: isolate; overflow: hidden;
  padding: var(--space-6); margin-bottom: var(--space-6); border-radius: 20px;
  border: 1px solid var(--border);
  background: linear-gradient(115deg, var(--amber-soft), var(--surface) 55%, var(--violet-soft));
  box-shadow: var(--shadow-sm);
}
.hb-catalog .page-h::after {
  content: ""; position: absolute; z-index: -1; pointer-events: none;
  width: 280px; height: 280px; right: -90px; top: -125px; border-radius: 50%;
  background: radial-gradient(circle at 35% 65%, var(--violet-soft), var(--blue-soft) 65%, transparent 70%);
  opacity: .7;
}
.hb-catalog .hb-eyebrow { color: var(--ink-2); }
.hb-catalog .page-h .lede { margin-bottom: 0; }
.hb-catalog .category { margin-bottom: var(--space-5); }
.hb-catalog .category-header { padding-bottom: var(--space-3); margin-bottom: var(--space-3); }
.hb-catalog .category-title { text-transform: none; letter-spacing: 0; font-size: var(--t-body); color: var(--ink-2); }
.hb-catalog .module-grid { gap: var(--space-3); padding: 0; grid-template-columns: repeat(auto-fill,minmax(300px,1fr)); }
.hb-catalog .module-tile {
  display: grid; grid-template-columns: 48px minmax(0,1fr); gap: var(--space-2) var(--space-3);
  align-content: start; padding: var(--space-4); border-radius: 16px;
  background: linear-gradient(125deg, var(--surface) 45%, var(--catalog-soft, var(--surface-2)));
}
.hb-catalog .module-tile:hover { box-shadow: var(--shadow-md); }
.hb-catalog .module-icon { grid-row: 1 / 3; width: 48px; height: 48px; border-radius: 14px; box-shadow: 0 2px 5px rgba(21,23,26,.06); }
.hb-catalog .module-icon svg { width: 23px; height: 23px; }
.hb-catalog .module-title { font-size: var(--t-body); padding-right: var(--space-4); }
.hb-catalog .module-subtitle { font-size: var(--t-small); line-height: 1.6; margin: 0; }
.hb-catalog .module-arrow { display: flex; position: absolute; top: var(--space-4); right: var(--space-3); color: var(--ink-3); opacity: .6; transform: none; }
.hb-catalog .module-arrow svg { width: 14px; height: 14px; }
.hb-briefing .col { max-width: 760px; }
.hb-briefing .c { padding: var(--space-5); }
.hb-briefing .c-t { font-size: var(--t-title); }
.hb-briefing .ask { box-shadow: var(--shadow-sm); border: 1px solid var(--border); }
.hb-briefing .ask input { min-width: 0; width: 0; flex: 1 1 0%; }
.hb-room .views { gap: var(--space-2); }
.hb-room .view-tabs { display: flex; gap: var(--space-1); min-width: 0; }
.hb-room .view-tab { font-size: var(--t-small); }
.hb-notes .bar, .hb-forms .bar { background: var(--surface); border: 1px solid var(--border); padding: var(--space-3) var(--space-4); border-radius: var(--radius-2); }
.hb-notes .empty, .hb-forms .empty { padding-block: var(--space-7); }
.hb-notes .nrow { padding-inline: var(--space-4); }
.hb-notes .hb-empty { background: transparent; border: 0; box-shadow: none; padding: var(--space-6) var(--space-4); }

/* Rental summary: the fifth metric spans the row on a phone. */
.rv-dashboard-stats { gap: var(--space-3); margin-bottom: var(--space-5); }
.rv-stat { padding: var(--space-4); }
.rv-stat-label { text-transform: none; letter-spacing: 0; font-size: var(--t-small); font-weight: var(--w-medium); }
.rv-stat-value { font-size: var(--t-hero); margin-top: var(--space-2); }

/* Apps is the launcher: its grid owns module selection. Keep its rail small
   instead of repeating every destination beside the same destinations. */
@media not all and (max-width: 768px) {
  .hb-catalog { --hb-rail-w: 84px; }
  .hb-catalog .hb-rail { width: var(--hb-rail-w); align-items: center; padding: var(--space-5) var(--space-2); }
  .hb-catalog .hb-rail-mark { align-self: center; margin-left: 0; }
  .hb-catalog .hb-workspace-link { width: 64px; min-height: 56px; flex-direction: column; justify-content: center; gap: var(--space-1); padding: var(--space-2); font-size: var(--t-small); }
  .hb-catalog .hb-workspace-link span { display: block; }
  .hb-catalog .hb-rail-foot { margin-top: auto; flex-direction: column; padding-inline: 0; }
  .hb-catalog .hb-rail-account { flex-direction: column; gap: var(--space-1); }
  .hb-catalog .hb-account-label { display: block; }
  /* 84px is room for a word, not for an address — and a name cut to "Maddi…"
     tells somebody less than "Account" does. The lockup goes the same way: this
     rail is as narrow as the column, so it keeps the short mark. */
  .hb-catalog .hb-rail.hb-knows-me .hb-account-word { display: block; }
  .hb-catalog .hb-rail.hb-knows-me .hb-account-name,
  .hb-catalog .hb-rail.hb-knows-me .hb-account-mail { display: none; }
  .hb-catalog .hb-rail .hb-rail-mark {
    --hb-logo-h: 30px;
    width: 40px; height: 40px; border-radius: 12px;
    justify-items: center;
    background: rgba(255, 255, 255, .72); border: 1px solid var(--border);
  }
  .hb-catalog .hb-rail .hb-rail-mark img.hb-logo-full { display: none; }
  .hb-catalog .hb-rail .hb-rail-mark img.hb-logo-compact { display: block; }
  .hb-catalog .hb-rail .hb-rail-mark:not(:has(img.hb-logo)) .hb-wordmark:not(.hb-wordmark-compact) { display: none; }
  .hb-catalog .hb-rail .hb-rail-mark:not(:has(img.hb-logo)) .hb-wordmark-compact { display: inline-flex; }
  .hb-catalog .hb-me-menu { left: calc(var(--hb-rail-w) + var(--space-2)); }
}

@media (max-width: 768px) {
  .hb-signin .login-left { justify-content: flex-start; padding: max(var(--space-7),env(safe-area-inset-top)) var(--space-4) var(--space-6); }
  .hb-signin .login-form-wrap { border-radius: var(--radius-2); box-shadow: var(--shadow-sm); }
  .hb-signin .login-brand { margin-bottom: var(--space-5); }
  .hb-signin input { font-size: 16px; }
  /* Fixed, named destinations replace the horizontal strip of 19 icons.
     Every permitted module remains available on Apps. The current module
     stays visible here, and setup/account controls remain reachable. */
  /* ── THE BAR FLOATS, AND THE PAGE SHOWS THROUGH IT ──────────────────────
     Asked for: "can the bottom menu bar be floating Liquid Glass?" — and it
     is the same complaint as "white panels at the bottom", one step on.

     IT WAS ALREADY MEANT TO BE GLASS. harris-canvas.css gives this bar
     `rgba(255,255,255,.86)` and `backdrop-filter: blur(12px)`. This file
     loads after it and set `background: var(--surface)` — flat #FFFFFF — so
     the blur stayed and had nothing left to show through. An opaque bar with
     a backdrop filter on it is the most expensive way to draw white.

     Glass needs three things and the background is only the first. It has to
     be INSET from the edges, or it reads as a panel bolted to the bottom of
     the screen rather than something resting above the page. It needs a light
     top edge, because that is the whole visual trick: a bright line where a
     real pane would catch the light, and a shadow under it for the gap. And
     it has to SATURATE as well as blur — blur alone turns the colour behind
     it to grey mud, which is what makes most attempts at this look like
     frosted plastic.

     AND THE FIRST GO AT IT WAS STILL A WHITE PILL. 62% white is a scrim: over
     Hank's own pale ground there is nothing left to see through, so the bar
     read as plastic however much blur sat behind it. Glass is mostly
     TRANSMISSION — the tint is a breath on top of the backdrop filter, not the
     material itself — and what sells it on a pale page is not the fill at all
     but the EDGE. A real pane catches light brightest where it turns away from
     you and almost not at all along the sides, so the rim here is a gradient
     travelling round the curve rather than one even hairline, and the filter
     lifts and firms the backdrop as a lens would instead of only frosting it.
     Measured over colour scrolled under the bar, which is the only way to tell
     the two apart: on the pale gradient alone, glass and plastic are both
     white. */
  .hb-canvas, .hb-railed {
    --hb-rail-w: 0px;
    --hb-rail-gap: var(--space-3);
    --hb-rail-bar: 64px;
    /* What the bar costs the page: its own height, the gap it floats above,
       and the home indicator under that. Pages fix their own bars against
       this (PM EOM's submit bar reads it), so it stays "room taken from the
       bottom of the screen" rather than becoming just the bar's height. */
    --hb-rail-h: calc(var(--hb-rail-bar) + var(--hb-rail-gap)
                  + max(var(--hb-rail-gap), env(safe-area-inset-bottom)));
  }
  .hb-rail {
    left: var(--hb-rail-gap);
    right: var(--hb-rail-gap);
    bottom: max(var(--hb-rail-gap), env(safe-area-inset-bottom));
    width: auto;
    height: var(--hb-rail-bar);
    gap: var(--space-1);
    padding: 6px var(--space-2);
    border-radius: 999px;
    /* A hairline of its own, under the travelling rim below, so that the two
       fallbacks have something to recolour when the rim is off. */
    border: 1px solid rgba(255, 255, 255, .34);
    border-right: 1px solid rgba(255, 255, 255, .34);
    /* The tint: brighter along the top where a pane picks up the sky, thinnest
       through the middle where you are meant to be looking through it. */
    background: linear-gradient(180deg,
                  rgba(255, 255, 255, .34),
                  rgba(255, 255, 255, .20) 46%,
                  rgba(255, 255, 255, .28));
    /* Blur to separate it from the page; saturate because blur desaturates and
       the colour behind is the whole point; brightness and contrast because
       glass is a LENS — it lifts what is under it rather than only fogging it,
       and that lift is also what keeps the labels readable when something dark
       scrolls beneath. */
    -webkit-backdrop-filter: blur(30px) saturate(210%) brightness(1.08) contrast(1.04);
    backdrop-filter: blur(30px) saturate(210%) brightness(1.08) contrast(1.04);
    /* Top specular, a softer catch along the bottom, a faint inner bloom, then
       the gap it is floating over. */
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .78),
                inset 0 -1px 0 rgba(255, 255, 255, .30),
                inset 0 0 24px rgba(255, 255, 255, .14),
                0 14px 34px -12px rgba(21, 23, 26, .30),
                0 2px 8px rgba(21, 23, 26, .07);
  }
  /* THE RIM, drawn as a ring rather than a border, because a border is one
     even colour the whole way round and light is not. Bright at the top-left
     shoulder, all but gone along the flanks, catching again at the bottom-right
     — the thing your eye reads as a curved edge rather than a drawn outline.
     A gradient filling the box, masked to its own 1px padding ring. */
  .hb-rail::after {
    content: "";
    position: absolute;
    inset: 0;
    padding: 1px;
    border-radius: inherit;
    pointer-events: none;
    background: linear-gradient(145deg,
                  rgba(255, 255, 255, .98) 0%,
                  rgba(255, 255, 255, .42) 26%,
                  rgba(255, 255, 255, .10) 50%,
                  rgba(255, 255, 255, .44) 74%,
                  rgba(255, 255, 255, .92) 100%);
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    mask-composite: exclude;
  }
  /* Rounded ends want their contents to keep clear of the curve. */
  .hb-rail-home { padding-inline: var(--space-1); }
  /* THE PRICE OF TRANSMISSION: the labels are a fixed grey, and a bar you can
     see through is a bar that can have something dark pass under it. A white
     glow on the glyphs is what a vibrant label does — invisible on the pale
     ground the app actually has, and the only thing holding the word apart
     from a dark card scrolling beneath it. */
  .hb-rail .hb-workspace-link span,
  .hb-rail .hb-rail-label,
  .hb-rail .hb-account-label {
    text-shadow: 0 0 3px rgba(255, 255, 255, .9), 0 0 9px rgba(255, 255, 255, .7);
  }
  .hb-rail .hb-workspace-link svg,
  .hb-rail a.hb-rl.here svg {
    filter: drop-shadow(0 0 5px rgba(255, 255, 255, .8));
  }
  /* WITHOUT THE FILTER IT HAS TO BE READABLE, not a pale smear over the
     gradient — Firefox on Android still ships without backdrop-filter. There is
     no transmission to be had here, so the tint does the whole job. */
  @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .hb-rail { background: rgba(255, 255, 255, .94); }
  }
  /* And somebody who has asked for less of this gets a solid bar. The shape
     and the float stay; it is the transparency they turned off — including the
     rim, which is a light effect and has nothing to catch on an opaque bar. */
  @media (prefers-reduced-transparency: reduce) {
    .hb-rail {
      background: var(--surface);
      -webkit-backdrop-filter: none;
      backdrop-filter: none;
      border-color: var(--border);
    }
    .hb-rail::after { display: none; }
  }
  .hb-rail-home { flex: 2; min-width: 0; flex-direction: row; gap: var(--space-1); }
  .hb-workspace-link { flex: 1; min-width: 0; height: 56px; flex-direction: column; gap: var(--space-1); font-size: var(--t-small); }
  .hb-workspace-link span { display: block; }
  .hb-rail-links { flex: 1; overflow: visible; padding: 0; border: 0; justify-content: center; }
  .hb-rail-links:not(:has(.here)) { display: none; }
  .hb-rail a.hb-rl { display: none; }
  .hb-rail a.hb-rl.here { display: flex; flex-direction: column; justify-content: center; gap: var(--space-1); width: 100%; height: 56px; }
  .hb-rail-label { display: block; max-width: 82px; font-size: var(--t-small); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .hb-rail-foot { flex: none; width: auto; padding: 0; border: 0; justify-content: center; gap: 4px; }
  .hb-rail-account { display: none; }
  .hb-rail.hb-apps-unavailable .hb-rail-account { display: flex; flex-direction: column; }
  .hb-rail:not(.hb-apps-unavailable) .hb-rail-foot:has([data-hb-setup][hidden]) { display: none; }
  .hb-rail-me { width: 44px; height: 44px; min-height: 44px; }
  .hb-rail-account { padding-inline: 4px; gap: 0; }
  .hb-account-label { display: block; font-size: var(--t-small); line-height: 1.1; }
  .hb-setup { flex: none; width: 44px; height: 44px; }
  .hb-room { min-height: 100dvh; padding: 0 0 calc(var(--hb-rail-h) + 92px); }
  .hb-railed { padding-bottom: calc(var(--hb-rail-h) + 92px); }
  body.hb-canvas:not(:has(.sidebar)) .hb-room > .wrap { padding: var(--space-5) var(--space-4); }
  .hb-room .page-h h1 { font-size: var(--t-page); gap: var(--space-3); letter-spacing: -.025em; }
  .hb-room .page-h h1 .hb-module-mark { width: 36px !important; height: 36px !important; }
  .hb-room .page-h h1 .hb-module-mark svg { width: 18px; height: 18px; }
  .hb-room .page-h .lede { font-size: var(--t-body); line-height: 1.6; }
  .hb-room .viewbar-inner { width: 100%; }
  .hb-room .viewbar a { min-height: 44px; }
  .hb-room .ph-actions { gap: var(--space-2); }
  .hb-room .ph-actions .input-modern { flex: 1; min-width: 0; }
  .hb-room .hm-grid { gap: var(--space-2); grid-template-columns: repeat(2,minmax(0,1fr)); }
  .hb-room .hm-card { padding: var(--space-3); }
  .hb-room .hm-card .mc-label { font-size: var(--t-small); }
  .hb-room .hm-card .mc-value { font-size: var(--t-page); }
  .hb-room .hm-card .mc-hint { font-size: var(--t-small); }
  .hb-me-menu { bottom: calc(var(--hb-rail-h) + var(--space-2)); }
  .hb-ai { right: var(--space-4); bottom: calc(var(--hb-rail-h) + var(--space-3)); min-height: 44px; }
  .hb-catalog .module-grid { grid-template-columns: minmax(0,1fr); gap: var(--space-2); }
  .hb-catalog .page-h { padding: var(--space-4); margin-bottom: var(--space-5); }
  .hb-catalog .module-tile { grid-template-columns: 40px minmax(0,1fr); padding: var(--space-4); gap: 4px var(--space-3); }
  .hb-catalog .module-icon { width: 40px; height: 40px; }
  .hb-catalog .module-icon svg { width: 20px; height: 20px; }
  .hb-catalog .module-subtitle { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
  .hb-catalog .category-title { font-size: var(--t-small); }
  .hb-briefing .c { padding: var(--space-4); }
  .hb-room .views { display: flex; flex-direction: column; align-items: stretch; gap: 0; }
  .hb-room .view-tabs { width: 100%; overflow-x: auto; }
  .hb-room .view-tab { flex: none; min-height: 44px; justify-content: center; padding-inline: var(--space-2); font-size: var(--t-small); }
  .hb-room .views-right { display: flex; justify-content: flex-end; margin: var(--space-3) 0 0; }
  .hb-room .views-right select { flex: 1; min-width: 0; }
  .hb-notes .bar, .hb-forms .bar { padding: var(--space-2) var(--space-3); }
  .hb-notes #viewOne .bar { display: grid; grid-template-columns: minmax(0,1fr) auto auto; gap: var(--space-2); }
  .hb-notes #viewOne .bar .spacer { display: none; }
  .hb-notes #backBtn { grid-column: 1; justify-self: start; }
  .hb-notes #oneWho { grid-column: 2 / 4; justify-self: end; }
  .hb-notes #saveState { grid-column: 1; font-size: var(--t-small); color: var(--ink-3); }
  .hb-notes #discardBtn { grid-column: 2; padding-inline: var(--space-2); font-size: var(--t-small); }
  .hb-notes #saveBtn { grid-column: 3; padding-inline: var(--space-3); }
  .rv-stat { padding: var(--space-3); }
  .rv-stat-value { font-size: var(--t-page); margin-top: var(--space-1); }
  .rv-dashboard-stats .rv-stat:last-child { grid-column: 1 / -1; display: flex; align-items: center; justify-content: space-between; }
  .rv-dashboard-stats .rv-stat:last-child > div:first-child { gap: var(--space-3); align-items: center; flex-direction: row-reverse; }
  .rv-dashboard-stats .rv-stat:last-child .rv-stat-value { margin-top: 0; }
  /* Keep all assessment fields available without a horizontal table swipe.
     Column headers remain in the accessibility tree; labels repeat visually. */
  .rv-assessments-table, .rv-assessments-table tbody { display: block; width: 100%; }
  .rv-assessments-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .rv-assessments-table tbody tr { display: grid; grid-template-columns: repeat(2,minmax(0,1fr)); gap: var(--space-3); padding: var(--space-4); border-bottom: 1px solid var(--border); }
  .rv-assessments-table tbody tr:last-child { border-bottom: 0; }
  .rv-assessments-table tbody td { display: block; padding: 0; border: 0; white-space: normal; font-size: var(--t-body); }
  .rv-assessments-table tbody td:first-child { grid-column: 1 / -1; }
  .rv-assessments-table tbody td:first-child a { margin: 0; padding: 0 0 var(--space-2); min-height: 44px; }
  .rv-assessments-table td[data-label]::before { content: attr(data-label); display: block; font-size: var(--t-small); font-weight: var(--w-medium); color: var(--ink-3); margin-bottom: 4px; text-transform: none; }
  /* 16px prevents automatic field zoom in iOS Safari. */
  .hb-room :is(input:not([type=checkbox]):not([type=radio]), select, textarea) { font-size: 16px; }
}
@media (prefers-reduced-motion: reduce) {
  .hb-surface-live { transition: none; }
  .hb-surface-live:hover { transform: none; }
}

/* ── 44px UNDER A FINGER, AT EVERY WIDTH ─────────────────────────────────────
   THE BAND BETWEEN 769px AND 1099px HAD NO RULE, and that band contains a
   tablet held in portrait. The Today/Apps pair is 40x40 in the base rule; the
   phone dock makes it 56px tall under `max-width: 768px` and the wide rail
   makes it full width under `min-width: 1100px`, so in between it kept the
   40px it was declared with — a touch device, with a 40px target, at 808px
   and 900px, on all 23 pages the sweep walks.
   Written here and not as another width, because the fault is not about width:
   it is about what is doing the pointing. The sweep's own 44px check is
   touch-only for exactly this reason — the rules that make it true live in
   `@media (pointer: coarse)` — so this is where the answer belongs, and it
   covers the next band nobody has thought of as well as this one.
   `min-*` rather than `width`/`height` so the two blocks that do have an
   opinion keep it: 56px tall on the dock and full width in the wide rail are
   both larger than this floor, and a floor does not argue with them. It sits
   after both so that nothing re-declares the minimum underneath it. */
@media (pointer: coarse) {
  .hb-workspace-link { min-width: 44px; min-height: 44px; }
}

/* ── MY DAY'S LEFT COLUMN ────────────────────────────────────────────────────
   A narrow column of sources rather than a list of modules. The shape is a
   floating white capsule holding the places the day's contents arrive from,
   with the two surfaces — calendar and documents — standing free underneath
   it, and the person's own face at the foot.

   WHY IT STAYS NARROW AT EVERY WIDTH. Every other page opens its rail to 216px
   above 1100px so the module names can be read. There are no names to read
   here: a source is its own logo, and six logos in a 216px column is 140px of
   white space down the left of somebody's morning. So this rail overrides the
   width rather than inheriting it, which is why the declarations below repeat
   inside the 1100px block — the shared rule is more specific there, and a
   width set once outside it loses. */
/* DESKTOP ONLY. The phone rail is a 64px dock at the bottom with its own
   shape, and `--hb-rail-w` is 0 there so the page keeps its full width.
   Setting the width outside a query overrode that at every size: the column
   stayed a column on a phone, the room kept an 84px left gutter, and the
   dock's two buttons were squeezed from 168px to 28px. Measured at 390px,
   where a card went from 322px to 274px.

   768 AND NOT 769, because 560 and 768 are the app's two canonical widths and
   __tests__/breakpoints refuses a fourteenth arbitrary one — rightly: the app
   used to respond at fifteen widths with no two pages agreeing. The cost is
   that both this and the dock's `max-width: 768px` apply at exactly 768px, so
   the dock block at the foot of this file puts `--hb-rail-w` back to 0 and
   wins there on order. */
@media (min-width: 768px) {
  body[data-hb-rail="sources"] { --hb-rail-w: 84px; }
  .hb-rail-day {
    width: var(--hb-rail-w);
    align-items: center;
    padding: var(--space-4) var(--space-2);
    gap: var(--space-4);
    /* THE WARM GROUND, NOT THE COOL GRADIENT. The module rail fades to violet
       at its foot, which reads as a panel attached to the app. This column sits
       on the canvas the briefing sits on and is held together by the capsule
       inside it, so the column itself is the page showing through. */
    background: none;
    border-right: 0;
  }
  .hb-rail-day .hb-rail-mark {
    width: 48px; height: 48px;
    --hb-logo-h: 26px;
    background: var(--surface);
    border: 1px solid rgba(255, 255, 255, .9);
    border-radius: var(--radius-3);
    box-shadow: 0 1px 2px rgba(21, 23, 26, .06), 0 6px 16px -10px rgba(21, 23, 26, .22);
  }
  /* HIDDEN, NOT ABSENT. The pair is in the DOM so the phone launcher has
     something to bind to and the dock below 768px is unchanged; the design puts
     nothing between the mark and the capsule, so on a column it is not drawn. */
  /* ── TODAY AND APPS STAY ON THE PIN RAIL ──────────────────────────────
     They used to be hidden here, because the sources column was My Day's own
     and My Day was where Today pointed. The rail is now every page's, and the
     business asked for exactly this: "the defaults at the top should include
     the 'today' and the 'apps' icons with other defaults + pinned items".

     Apps is also the ONLY route to a module nobody has pinned, so hiding it
     on this rail would leave the unpinned half of the application reachable
     only by typing a URL. */
  .hb-rail-day .hb-rail-home {
    display: flex; flex-direction: column; align-items: center;
    gap: 2px; width: 100%;
  }
  /* Icon-only at this width: the labels belong to the 216px rail. */
  .hb-rail-day .hb-rail-home .hb-workspace-link {
    width: 44px; min-height: 44px; justify-content: center; padding: 0;
    border-radius: var(--radius-3);
  }
  .hb-rail-day .hb-rail-home .hb-workspace-link span { display: none; }
  .hb-day { display: flex; flex-direction: column; align-items: center; gap: var(--space-3); flex: 1; min-height: 0; }

  /* The capsule. One object with a lit edge, the same trade `.modal` makes:
     a white hairline and the lift in the shadow, so it reads as floating on the
     ground rather than as a box drawn on it. */
  .hb-day-pill {
    display: flex; flex-direction: column; align-items: center; gap: 2px;
    min-height: 0;
    padding: 6px;
    background: var(--surface);
    border: 1px solid rgba(255, 255, 255, .9);
    border-radius: 22px;
    box-shadow: 0 0 0 1px rgba(21, 23, 26, .04), 0 1px 2px rgba(21, 23, 26, .06),
                0 10px 24px -14px rgba(21, 23, 26, .26);
  }
  /* Empty until the answer lands, and an empty capsule is a white pebble with a
     shadow — so it is not drawn at all until it holds something. */
  .hb-day-pill:not(:has(.hb-day-src)) { display: none; }
  .hb-day-first,
.hb-day-rest { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.hb-day-rest[hidden] { display: none; }

  /* ── THE REST SCROLLS, THE PINNED BLOCK DOES NOT ─────────────────────────
     "Every module, but it scrolls below whats pinned as we have alot of them."
     Twenty apps at 44px is 880px of tiles, which is taller than most laptops
     once the mark, the sources, the chevron and the two surfaces are counted —
     so expanding would push the calendar and the documents off the bottom of
     the screen, and the column would end somewhere nobody can reach.
     The fixed block keeps its full height and this one takes what is left:
     `min-height: 0` because a flex child will otherwise refuse to shrink below
     its content and overflow the column instead of scrolling inside it, which
     is the whole trap of nesting a scroller in a flex column. */
  .hb-day-rest {
    /* THE WHOLE CHAIN HAS TO ALLOW IT, which is the trap. A flex item's
       automatic minimum size is its CONTENT, so every ancestor between the
       bounded height and this scroller must be told it may shrink below that
       or the overflow simply happens further up and the column runs off the
       bottom of the window. Measured before and after: 20 apps made this
       region 966px tall inside an 860px window and it did not scroll — the
       tiles at the end were laid out past the viewport, where nothing could
       reach them. `.hb-day-pill` carries the same `min-height: 0` for the
       same reason. */
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    /* Room for the tip chips, which sit outside the tile. */
    scrollbar-width: thin;
  }
  .hb-day-rest::-webkit-scrollbar { width: 0; }
  .hb-day-mods { display: flex; flex-direction: column; align-items: center; gap: 2px; }


  /* ── Choosing pins ──────────────────────────────────────────────────────
     The mode is visible on every tile at once, because a mode that looks like
     the thing it is not is how somebody navigates away mid-task: pressing a
     tile here pins it, and nothing about a tile otherwise says so. */
  .hb-day-src.is-picking { box-shadow: inset 0 0 0 1px var(--border); }
  .hb-day-pin {
    /* INSIDE THE TILE, NOT HANGING OFF IT. At -2px the badge sat in the 2px
       gap and touched the tile above, which in a column of nine reads as one
       smudged edge rather than nine states. */
    position: absolute; top: 2px; right: 2px;
    width: 14px; height: 14px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    background: var(--surface); color: var(--ink-3);
    box-shadow: 0 0 0 1px var(--border);
  }
  .hb-day-pin svg { width: 9px; height: 9px; }
  .is-picking.is-pinned .hb-day-pin { background: var(--blue-ink); color: #fff; box-shadow: none; }
  .hb-day-pick {
    position: relative;
    display: flex; align-items: center; justify-content: center;
    width: 44px; height: 44px; flex: none; margin-top: 2px;
    border: 0; background: none; padding: 0; border-radius: 14px;
    color: var(--ink-3); cursor: pointer;
  }
  .hb-day-pick svg { width: 15px; height: 15px; }
  .hb-day-pick:hover { background: var(--surface-2); color: var(--ink-2); }
  .hb-day-pick:focus-visible { outline: 2px solid var(--blue-ink); outline-offset: 2px; }
  .hb-day-pick.is-picking { background: var(--blue-soft); color: var(--blue-ink); }

  /* The right-click menu. On the body rather than inside the capsule, so the
     apps scroller cannot clip it — the trap the hover chips were moved out of. */
  .hb-day-menu {
    position: fixed; z-index: 60;
    background: var(--surface);
    border-radius: var(--radius-2);
    padding: 4px;
    box-shadow: 0 0 0 1px rgba(21, 23, 26, .06), 0 10px 28px -10px rgba(21, 23, 26, .3);
  }
  .hb-day-menu-item {
    display: flex; align-items: center; gap: var(--space-2);
    width: 100%; min-height: 36px; padding: 0 var(--space-3) 0 var(--space-2);
    border: 0; background: none; border-radius: var(--radius-3);
    color: var(--ink); font-size: var(--t-small); font-weight: var(--w-medium);
    white-space: nowrap; cursor: pointer;
  }
  .hb-day-menu-item svg { width: 13px; height: 13px; color: var(--ink-3); }
  .hb-day-menu-item:hover { background: var(--surface-2); }
  .hb-day-menu-item:focus-visible { outline: 2px solid var(--blue-ink); outline-offset: -2px; }


  .hb-day-src {
    position: relative;
    display: flex; align-items: center; justify-content: center;
    /* 44px, because this is a control and the width sweep is right about it. */
    width: 44px; height: 44px; flex: none;
    border: 0; background: none; padding: 0;
    border-radius: 14px;
    color: var(--ink-2);
    cursor: pointer;
    transition: background 120ms ease, transform 120ms ease;
  }
  .hb-day-src svg { width: 22px; height: 22px; display: block; }
  .hb-day-src:hover { background: var(--surface-2); }

  /* ── A PINNED TILE AND ITS UNPIN CONTROL ────────────────────────────────
     The slot exists so the × can be a SIBLING of the anchor rather than a
     child of it: a <button> inside an <a> is invalid markup whose clicks
     navigate instead of acting.

     Shown on hover and on focus-within. The focus half is not decoration —
     it is the only keyboard route to unpinning now that the "Pin apps" mode
     is gone, and a control that appears solely under a pointer is one a
     keyboard never reaches. */
  .hb-day-slot { position: relative; display: block; width: 44px; flex: none; }
  .hb-day-unpin {
    position: absolute; top: -2px; right: -2px; z-index: 2;
    width: 18px; height: 18px; min-height: 0; padding: 0;
    display: none; align-items: center; justify-content: center;
    font-size: 12px; line-height: 1;
    border: 1px solid var(--border); border-radius: 50%;
    background: var(--surface); color: var(--ink-2); cursor: pointer;
  }
  .hb-day-slot:hover .hb-day-unpin,
  .hb-day-slot:focus-within .hb-day-unpin { display: flex; }
  .hb-day-unpin:hover { background: var(--surface-2); color: var(--ink); }
  .hb-day-unpin:focus-visible { outline: 2px solid var(--blue-ink); outline-offset: 1px; display: flex; }
  /* ON TOUCH THE × IS NOT THE ROUTE. 18px is below the target this app holds
     itself to, and a 44px control cannot sit in the corner of a 44px tile —
     so a long press opens the same menu the right-click does, whose item is
     a full-size target. */
  @media (pointer: coarse) { .hb-day-unpin { display: none !important; } }
  .hb-day-src.here { background: var(--surface-2); color: var(--ink); box-shadow: inset 0 0 0 1px var(--border); }
  .hb-day-src:focus-visible { outline: 2px solid var(--blue-ink); outline-offset: 2px; }

  /* ── THE COUNT ON A TILE ─────────────────────────────────────────────────
     Asked for: "badges on the Outlook and Teams tiles". Four decisions in it.

     INSIDE THE TILE, NOT HANGING OFF THE CORNER, and the pin badge thirty
     lines up records why: at -2px it sat in the 2px gap between tiles and
     touched the one above, so a column of nine read as one smudged edge
     rather than nine states. Same column, same gap, same answer.

     12px, WHICH IS THE FLOOR. It is the smallest type this application sets
     and it is `MIN_TEXT` in the width sweep — a 10px badge would hold more
     digits and would be precisely what that check exists to catch. The pill
     grows sideways instead, which is why the width is a `min-width`.

     ONE INK FOR EVERY BADGE, not the source's own brand colour. The number is
     Hank's annotation on somebody else's icon; in Outlook blue on the Outlook
     mark it would read as part of the logo rather than as something counted.
     White on `--blue-ink` is 5.2:1.

     AND A RING IN THE TILE'S OWN GROUND, so the pill reads as sitting on the
     mark rather than as a hole cut out of it. */
  .hb-day-badge {
    position: absolute; top: 1px; right: 1px;
    box-sizing: border-box;
    min-width: 16px; height: 16px; padding: 0 4px;
    display: flex; align-items: center; justify-content: center;
    border-radius: var(--radius-sm);
    background: var(--blue-ink); color: #fff;
    font-size: 12px; font-weight: var(--w-medium); line-height: 1;
    font-variant-numeric: tabular-nums;
    box-shadow: 0 0 0 1.5px var(--surface);
  }
  /* A READ THAT FAILED IS NOT A COUNT AND MUST NOT LOOK LIKE ONE. Grey, and a
     question mark rather than a figure: Hank does not know. Quiet on purpose —
     a mailbox Graph could not reach for ten seconds is not an alarm — and the
     sentence that says which read went quiet is in the tile's own name. */
  .hb-day-badge.is-unsure { background: var(--ink-3); }

  /* ── A module tile wears its own colour ──────────────────────────────────
     The same `soft`/`ink` pair its card on the catalog and its link on every
     other rail already wear, passed in from the registry as custom properties
     so the column cannot come to disagree with the rest of the app about what
     colour a module is.

     AFTER `.hb-day-src`, AND THAT IS THE WHOLE BUG IT FIXES. These rules were
     written thirty lines further up, where `.hb-day-src { color: var(--ink-2) }`
     sat after them — same specificity, one class each, so source order decided
     and every module in the column drew plain grey. The inline `--rl-ink` was
     set correctly on each tile the whole time and resolved to nothing visible.
     Reported as "still need these to be coloured not just plain". */
  .hb-day-mod { color: var(--rl-ink, var(--ink-2)); }
  .hb-day-mod svg { stroke: currentColor; }
  .hb-day-mod:hover { background: var(--rl-soft, var(--surface-2)); }
  /* PINNED IS A STATE YOU CAN SEE WITHOUT COUNTING. The soft wash is the same
     one the module's own card uses, so a pinned tile reads as the module
     rather than as a tile wearing a highlight. */
  .hb-day-mod.is-pinned { background: var(--rl-soft, var(--surface-2)); }
  .hb-day-mod.here { background: var(--rl-soft, var(--surface-2)); color: var(--rl-ink, var(--ink)); }

  /* OFF IS DESATURATED, NOT RECOLOURED. The marks carry their own brand colours
     in the artwork, so one filter dims every one of them and a mark added later
     cannot forget to have an off state. It stays on the column rather than being
     removed from it: a source Hank could show and does not yet is a fact, and
     hiding it makes the column claim this is everything there is. */
  .hb-day-src.is-off {
    filter: grayscale(1) opacity(.42);
    cursor: default;
  }
  .hb-day-src.is-off:hover { background: none; }
/* EXCEPT THE ONE THEY CAN DO SOMETHING ABOUT. A tile offering a sign-in is
   still dim — it is still showing nothing — but it answers the pointer,
   because it is a control rather than a statement. */
.hb-day-src.is-off.is-offerable { cursor: pointer; }
.hb-day-src.is-off.is-offerable:hover { background: var(--surface-2); filter: grayscale(.4) opacity(.75); }

  /* The name, on hover and on focus, as a chip beside the column — a 44px tile
     cannot hold a word, and the title attribute alone never reaches a keyboard. */
  /* FIXED, NOT ABSOLUTE, AND THE SCROLLER IS WHY. harris-canvas.css records
     this exact bug against the module rail's own hover label: a scroll
     container clips its descendants at its padding box, so a chip positioned
     outside a 84px column is laid out, visible by every property you can read
     back, and drawn entirely inside the clip. Only a screenshot says
     otherwise. The apps below the pinned block now live in a scroller, so
     their chips need the same escape — an ancestor's overflow does not clip a
     fixed box. `top` is left alone so it resolves to the static position, and
     the rail is itself fixed, so the chip lines up with its tile without
     anything measuring. */
  .hb-day-tip {
    position: fixed; left: calc(var(--hb-rail-w, 84px) + 10px); transform: scale(.96);
    padding: 5px 10px; border-radius: var(--radius-2);
    background: var(--ink); color: var(--bg);
    font-size: var(--t-small); font-weight: var(--w-medium); white-space: nowrap;
    opacity: 0; pointer-events: none;
    transition: opacity 120ms ease, transform 120ms ease;
    z-index: 3;
  }
  .hb-day-src:hover .hb-day-tip,
  .hb-day-src:focus-visible .hb-day-tip,
  .hb-day-pick:hover .hb-day-tip,
  .hb-day-pick:focus-visible .hb-day-tip { opacity: 1; transform: scale(1); }

  /* The chevron that puts the capsule away. Outside the capsule rather than the
     last tile inside it, so collapsing does not move the control that collapses. */
  .hb-day-more {
    display: flex; align-items: center; justify-content: center;
    width: 44px; height: 30px; flex: none;
    border: 0; background: none; padding: 0; border-radius: 12px;
    color: var(--ink-3); cursor: pointer;
  }
  .hb-day-more svg { width: 18px; height: 18px; transition: transform 160ms ease; }
  .hb-day-more:hover { background: var(--surface-2); color: var(--ink-2); }
  .hb-day-more:focus-visible { outline: 2px solid var(--blue-ink); outline-offset: 2px; }
  .hb-day-more.is-closed svg { transform: rotate(180deg); }

  .hb-day-surfaces { display: flex; flex-direction: column; align-items: center; gap: var(--space-2); }
  /* Standing free on the ground, so they read as a different kind of thing from
     the sources in the capsule — which is what they are. */
  .hb-day-surfaces .hb-day-src { color: var(--ink-2); }
  .hb-day-surfaces .hb-day-src:hover { background: rgba(255, 255, 255, .72); }

  /* THE FOOT IS THE RING AND THE FACE. The name goes — there is no room for an
     address in an 84px column — but the setup ring stays, and taking it away
     was a real mistake rather than a tidy one.

     It is the control that reopens profile setup, and the width sweep's
     "onboarding" view is literally `["onboarding", "/", "[data-hb-setup]"]`:
     it opens the front door and clicks that button. `/` serves My Day for
     anybody whose landing view is the briefing, so hiding it here made
     finishing your own profile unreachable from the page most people start on.
     The sweep said so in the clearest words it had — "matched but could not be
     clicked — it has no box" — and the ceiling turned that into a red build,
     which is what the ceiling is for.

     It costs the design nothing in the ordinary case: the button carries
     `hidden` until the answer arrives and stays hidden for a profile that is
     complete, so the foot is just the face for almost everybody. */
  .hb-rail-day .hb-rail-foot {
    border-top: 0; padding-top: 0;
    flex-direction: column; align-items: center; justify-content: center;
    gap: var(--space-2);
  }
  .hb-rail-day .hb-account-label { display: none; }
  .hb-rail-day .hb-setup { flex: none; width: 44px; height: 44px; }
  .hb-rail-day .hb-rail-me { width: 44px; height: 44px; min-height: 44px; border-radius: 50%; }
}

@media (min-width: 1100px) {
  /* Repeated inside the breakpoint because the shared rule that opens the rail
     to 216px lives here and would otherwise win on order. */
  body[data-hb-rail="sources"] { --hb-rail-w: 84px; }
  .hb-rail-day { width: var(--hb-rail-w); align-items: center; padding: var(--space-4) var(--space-2); }
  .hb-rail-day .hb-rail-mark {
    align-self: center; margin-left: 0;
    width: 48px; height: 48px; max-width: none;
    --hb-logo-h: 26px;
    justify-items: center;
    background: var(--surface);
    border: 1px solid rgba(255, 255, 255, .9);
    border-radius: var(--radius-3);
  }
  /* The short mark at every width, like the narrow rail: 84px has no room for
     the lockup the 216px rail opens up for. */
  .hb-rail-day .hb-rail-mark img.hb-logo-full { display: none; }
  .hb-rail-day .hb-rail-mark img.hb-logo-compact { display: block; }
  .hb-rail-day .hb-rail-mark:not(:has(img.hb-logo)) .hb-wordmark:not(.hb-wordmark-compact) { display: none; }
  .hb-rail-day .hb-rail-mark:not(:has(img.hb-logo)) .hb-wordmark-compact { display: inline-flex; }
  .hb-rail-day .hb-rail-foot { flex-direction: column; justify-content: center; padding-inline: 0; }
  .hb-rail-day .hb-rail-account { justify-content: center; flex: none; }
  .hb-rail-day .hb-account-label { display: none; }
}

/* On a phone the rail is the bottom dock, which has its own shape and is not
   a column at all — the sources belong in the page there, not in a 64px bar
   that already holds the two ways on. */
@media (max-width: 768px) {
  /* THE OVERLAP AT EXACTLY 768px IS SETTLED HERE. Both this and the desktop
     block above match at that width; this one is later in the file and at the
     same specificity, so the dock wins — which is right, because 768px is a
     tablet holding the bar, not a desk. Measured: the width sweep drives 768px
     and reports the dock's two buttons at 168px, not 28px. */
  body[data-hb-rail="sources"] { --hb-rail-w: 0px; }
  .hb-rail-day {
    width: auto;
    background: var(--surface);
    padding: 0;
  }
  .hb-rail-day .hb-day { display: none; }
  /* And the dock comes back: Today and Apps are the two ways on, and on a
     phone they are the whole rail. */
  .hb-rail-day .hb-rail-home { display: flex; }
}
