/* Hologram Hub chrome: the parts every page of this site shares — the brand tokens, the resets, the
   shell, the shared controls, and the header with its top-level menu, theme switch and sign-in.
   Loaded by every page the build writes AND by the Registry page, which ships as its own file, so the
   header has exactly one definition and cannot drift between them.
   Every value resolves to the Hologram brand kit. Checked by scripts/lint-tokens.mjs. */

/* ---- product aliases over the brand kit */
:root {
  /* product aliases: references only */
  --hh-ground: var(--background);
  --hh-surface: var(--card);
  --hh-popover: var(--popover);
  --hh-fill: var(--muted);
  --hh-line: var(--border);
  --hh-line-strong: var(--input);
  --hh-line-focus: var(--ring);
  --hh-text: var(--foreground);
  --hh-text-dim: var(--muted-foreground);
  --hh-text-faint: var(--muted-foreground-subtle);
  --hh-accent: var(--brand);
  --hh-accent-text: var(--brand-foreground);
  /* The kit accent is 4.11:1 on the warm dark card and 4.13:1 on white — under AA for a 14px label, which
     is why nothing on this site sets words in it. The selected section still has to read as orange, so it
     takes the accent warmed toward whichever foreground the theme is using: 5.08:1 dark, 5.36:1 light. */
  --hh-accent-legible: color-mix(in srgb, var(--hh-accent) 80%, var(--hh-text));
  --hh-primary: var(--primary);
  --hh-primary-text: var(--primary-foreground);
  --hh-shadow: color-mix(in srgb, var(--background) 60%, transparent);
  --hh-ok: var(--success);
  --hh-bad: var(--destructive);
  --hh-wash: color-mix(in srgb, var(--foreground) 3%, transparent);

  /* control system: two heights, one tag height */
  --hh-control: var(--space-8);
  --hh-field: var(--space-10);
  --hh-tag: var(--space-6);
  --hh-avatar: var(--space-12);
  --hh-icon: var(--space-4);
  --hh-icon-small: var(--text-sm);
  --hh-ease: 150ms cubic-bezier(.4, 0, .2, 1);
  --hh-leading: 1.5;
  /* One size for every word on the site that is not a headline: the menu, the sign-in, the hero's line and
     its actions, the controls. The headlines are set in the display steps; everything else is this. */
  --hh-ui: var(--text-base);
  --hh-pad: var(--space-6);
  --hh-gutter: var(--space-6);
  /* The card mesh's box: src/card-art.mjs draws a viewBox of exactly this size, so one unit is one pixel
     and the facets match on every page. 260x200 composed from the kit's steps: 4x64+4, 3x64+8. */
  --hh-art-w: calc(var(--space-16) * 4 + var(--space-1));
  --hh-art-h: calc(var(--space-16) * 3 + var(--space-2));

  /* landing type: the kit's steps, sized by whichever of width or height is scarcer */
  --hh-display: clamp(var(--text-3xl), min(8.5vw, 11svh), calc(var(--text-6xl) * 1.3));
  /* The pinned strip: one mark plus the air above and below it. The landing reserves exactly this. */
  --hh-strip-mark: var(--space-10);
  --hh-strip-top: var(--space-6);
  --hh-strip-bottom: var(--space-10);
  --hh-strip-gap: var(--space-16);
  --hh-strip-label: var(--text-xl);
  --hh-strip: calc(var(--hh-strip-mark) + var(--hh-strip-top) + var(--hh-strip-bottom));
}
:root:not(.dark) { --hh-shadow: color-mix(in srgb, var(--foreground) 14%, transparent); --hh-wash: color-mix(in srgb, var(--foreground) 4%, transparent); }

/* ---- resets */
*, *::before, *::after { box-sizing: border-box; }
html { background: var(--hh-ground); }
body {
  margin: 0;
  background: var(--hh-ground);
  color: var(--hh-text);
  font-family: var(--font-sans);
  font-size: var(--hh-ui);
  font-weight: var(--weight-normal);
  line-height: var(--hh-leading);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-variant-numeric: tabular-nums;
}
::selection { background: var(--hh-text); color: var(--background); }
a { color: inherit; text-decoration: none; }
button, input { font: inherit; color: inherit; letter-spacing: inherit; }
button { background: none; border: 0; padding: 0; cursor: pointer; }
button:disabled { cursor: default; }
h1, h2, p, dl, dd { margin: 0; font-size: inherit; font-weight: inherit; }
ul { list-style: none; margin: 0; padding: 0; }
[hidden] { display: none !important; }
.i { width: var(--hh-icon); height: var(--hh-icon); flex: none; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
:focus-visible { outline: 2px solid var(--hh-line-focus); outline-offset: 2px; }

.shell { max-width: 120rem; margin: 0 auto; padding: var(--space-6) var(--hh-gutter) var(--space-16); }
@media (min-width: 992px) { :root { --hh-gutter: var(--space-8); } }
@media (max-width: 480px) { :root { --hh-gutter: var(--space-4); } }

/* ---- shared controls */
.control {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  height: var(--hh-control); padding: 0 var(--space-3);
  border: 1px solid var(--hh-line); border-radius: var(--radius-md);
  font-size: var(--text-sm); color: var(--hh-text-dim);
  transition: color var(--hh-ease), border-color var(--hh-ease), background var(--hh-ease), opacity var(--hh-ease);
}
.control:not(:disabled):hover { color: var(--hh-text); border-color: var(--hh-line-focus); }
.control:disabled { opacity: .45; }
.control.square { width: var(--hh-control); padding: 0; flex: none; }

.field {
  display: flex; align-items: center; gap: var(--space-3);
  height: var(--hh-field); padding: 0 var(--space-4);
  border: 1px solid var(--hh-line-strong); border-radius: var(--radius-md);
  color: var(--hh-text-dim);
  transition: border-color var(--hh-ease);
}
.field:hover, .field:focus-within { border-color: var(--hh-line-focus); }
.field input { flex: 1; min-width: 0; height: 100%; padding: 0; background: none; border: 0; outline: 0; color: var(--hh-text); }
.field input::placeholder { color: var(--hh-text-dim); }
.field input::-webkit-search-cancel-button { display: none; }
.field.compact { height: var(--hh-control); padding: 0 var(--space-3); gap: var(--space-2); font-size: var(--text-sm); }

.button {
  display: inline-flex; align-items: center; gap: var(--space-2);
  height: var(--hh-field); padding: 0 var(--space-4);
  border: 1px solid var(--hh-line-strong); border-radius: var(--radius-md);
  font-size: var(--hh-ui); white-space: nowrap;
  transition: border-color var(--hh-ease), opacity var(--hh-ease);
}
.button:hover { border-color: var(--hh-line-focus); }
.button.primary { background: var(--hh-primary); border-color: var(--hh-primary); color: var(--hh-primary-text); }
.button.primary .i { color: var(--hh-accent); stroke-width: 2.25; }
.button.primary:hover { opacity: .85; }
/* The brand kit's success pair: --success behind --success-foreground. Used for Download. */
.button.success { background: var(--success); border-color: var(--success); color: var(--success-foreground); }
.button.success .i { color: var(--success-foreground); stroke-width: 2.25; }
/* Hover adds a ring instead of dimming, so the fill is always exactly --success (the green of "Verified"). */
.button.success:hover, .button.success:focus-visible { border-color: var(--success); box-shadow: 0 0 0 var(--space-1) color-mix(in srgb, var(--success) 30%, transparent); }
.button:disabled { opacity: .5; }

.pill { display: inline-flex; align-items: center; height: var(--hh-control); padding: 0 var(--space-3); border-radius: var(--hh-control); background: var(--hh-fill); font-family: var(--font-mono); font-size: var(--text-sm); }

.panel { background: var(--hh-surface); border-radius: var(--radius-lg); padding: var(--hh-pad); }

/* ---- the lead: what a section page says first.
   One row above the columns on every catalogue page — Models, Registry, Spaces — in the same order and
   nothing else: the section's name, how many of its things are listed, and the address they are read from
   with a dot for whether it answered. Three pages, one row, so crossing between them moves nothing. Built
   pages write it in build.mjs; the pages that ship as their own files write the same markup, and
   qa/menu.mjs holds all three to it. */
/* The same air above the row as below it, on every page: what sits under the row is a sibling that follows
   it, not always the next one (the Models page keeps its hidden index control between), so the rule below
   in styles.css uses ~ and the row itself carries the whole of both margins. */
.lead { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); padding: var(--space-10) 0; }
.lead h1 { font-family: var(--font-display); font-size: var(--text-3xl); font-weight: var(--weight-medium); letter-spacing: var(--tracking-display); line-height: 1.2; }
/* The address. A chip the height of the count beside it, in the mono the address is written in. */
.endpoint { display: inline-flex; align-items: center; gap: var(--space-2); height: var(--hh-control); padding: 0 var(--space-3); border: 1px solid var(--hh-line-strong); border-radius: var(--radius-md); font-family: var(--font-mono); font-size: var(--text-sm); color: var(--hh-text-dim); white-space: nowrap; }
/* Copy-to-clipboard, and the shell prompt in front of a line you are meant to run. Both live here rather
   than in styles.css because the pages that ship as their own files load this sheet and not that one. */
.copy { display: inline-flex; align-items: center; gap: var(--space-2); color: inherit; transition: color var(--hh-ease); }
.copy .i { width: var(--hh-icon-small); height: var(--hh-icon-small); color: var(--hh-text-dim); }
.copy:hover, .copy:hover .i { color: var(--hh-text); }
.prompt { color: var(--hh-text-dim); margin-right: .5ch; }

/* The tag beside a section heading: the same control on all five sections. It is a button because it copies,
   and it wears .endpoint because what it shows is the section's address -- one look, whichever section you
   are in. Focus is the sheet-wide :focus-visible rule above; nothing here needs its own. */
.section-tag { background: none; cursor: pointer; font: inherit; font-family: var(--font-mono); font-size: var(--text-sm); color: var(--hh-text-dim); transition: color var(--hh-ease), border-color var(--hh-ease); }
.section-tag:hover { color: var(--hh-text); border-color: var(--hh-text-faint); }
.section-tag.copied { color: var(--hh-ok); border-color: var(--hh-ok); }
/* The line is a fixed length -- it is a command, so it cannot be shortened or truncated without ceasing to be
   one. On the narrowest phones the full command is wider than the gutter allows, so the tag steps down a size
   rather than pushing the page sideways. */
@media (max-width: 420px) {
  .section-tag { font-size: var(--text-xs); padding: 0 var(--space-2); }
}
.dot { width: var(--space-2); height: var(--space-2); border-radius: 50%; background: var(--hh-text-faint); flex: none; }
.dot.ok { background: var(--hh-ok); }
.dot.bad { background: var(--hh-bad); }

/* ---- header */
.top {
  position: sticky; top: var(--space-6); z-index: 10;
  display: flex; align-items: center; gap: var(--space-8);
  height: var(--space-16); padding: 0 var(--space-6);
  background: var(--hh-surface); border-radius: var(--radius-xl);
}
/* Scroll veil: content dissolves before it reaches the header instead of sliding under it. */
.veil {
  position: fixed; z-index: 9; top: 0; left: 0; right: 0; height: calc(var(--space-6) * 2 + var(--space-16));
  pointer-events: none; background: var(--background);
  -webkit-mask-image: linear-gradient(var(--hh-text) 64%, transparent);
  mask-image: linear-gradient(var(--hh-text) 64%, transparent);
}
.brand { display: flex; align-items: center; gap: var(--space-3); flex: none; }
.brand img { width: auto; display: block; }
.brand .on-light { display: none; }
:root:not(.dark) .brand .on-dark { display: none; }
:root:not(.dark) .brand .on-light { display: block; }
.brand .mark { height: var(--space-8); }
/* The wordmark stands at 20px beside the 32px mark: the lockup's own proportion, and the row's cap height. */
.brand .word { height: var(--space-5); }
.top-end { margin-left: auto; display: flex; align-items: center; gap: var(--space-6); font-family: var(--font-mono); font-size: var(--hh-ui); }
.top-search { width: 14.5rem; }
.status { display: flex; align-items: center; gap: var(--space-2); color: var(--hh-text-dim); transition: color var(--hh-ease); white-space: nowrap; }
.status:hover { color: var(--hh-text); }
.i.mark { fill: currentColor; stroke: none; }
.status::before { content: ""; width: var(--space-2); height: var(--space-2); border-radius: 50%; background: var(--hh-ok); }
@media (max-width: 1419px) { .top-search { display: none; } }
@media (max-width: 720px) {
  .top { gap: var(--space-4); padding: 0 var(--space-4); }
  /* The header still needs its room for the account control. */
  .brand .mark { height: var(--space-6); }
  .brand .word { height: var(--space-4); }
  .brand { gap: var(--space-2); }
  .top-end { gap: var(--space-2); }
  /* the same room the other header controls take: the mark alone says it */
  #sign-in-button .label { display: none; }
  #sign-in-button { width: var(--hh-control); padding: 0; justify-content: center; border-radius: 50%; }
}

/* The top-level menu. Sits at the end of the row, immediately before the icons. Each label carries a mark
   of its own: a grid for the catalogue, a package for the registry, a page for the guide. Three silhouettes
   that stay apart at 16px. Built by topNav() in build.mjs, and the same markup is put into the Registry
   page by the same build, so every page of the site carries this row and carries it identically. */
.top-nav { display: flex; align-items: center; gap: var(--space-6); font-family: var(--font-mono); font-size: var(--hh-ui); }
.top-nav a { display: inline-flex; align-items: center; gap: var(--space-2); color: var(--hh-text-dim); transition: color var(--hh-ease); }
.top-nav a:hover { color: var(--hh-text); }
/* The house 16px mark against the 16px label: the mark stands on the baseline and clears the cap height. */
.top-nav .i { width: var(--hh-icon); height: var(--hh-icon); }
/* Where you are, in the brand colour. aria-current carries the same fact to a screen reader, so the
   colour is a second telling and never the only one. */
.top-nav a[aria-current] { color: var(--hh-accent-legible); }

/* Everything after the brand is one group. Wide, the group is not a box at all: its children sit in the row
   exactly where they always did. The two icon controls keep the row's own spacing between them. */
.top-menu { display: contents; }
.top-tools { display: flex; align-items: center; gap: var(--space-6); }
/* The one control that stands in for the group on a narrow screen: the same circle as the theme switch, with
   three lines in it, and a cross once the sheet is open. It does not exist on a wide screen. */
.menu-button { display: none; place-items: center; width: var(--hh-control); height: var(--hh-control); border-radius: 50%; border: 1px solid var(--hh-line-strong); color: var(--hh-text); transition: border-color var(--hh-ease), transform var(--hh-ease); }
.menu-button:hover, .menu-button[aria-expanded="true"] { border-color: var(--hh-line-focus); }
.menu-button:active { transform: scale(.94); }
.menu-button .i { width: var(--hh-icon-small); height: var(--hh-icon-small); }
.menu-button .i + .i, .top.menu-open .menu-button .i:first-child { display: none; }
.top.menu-open .menu-button .i + .i { display: block; }
/* Folded, under 1100px: at the site's 16px text the five sections, the lockup and the two controls need
   about 1080px of row, so the fold sits just above that. The group becomes the screen: a panel over the whole viewport, the brand and the close button
   still in their corners above it, the sections as a column of display type a thumb cannot miss, and the
   theme switch and sign-in on a row at the foot. The button opens it; it, Escape, a tap on a section, or
   the window growing (chrome.js) closes it. The two controls' popovers unfold inside the panel rather than
   beside their controls: a popover hung off a control at the left edge of a phone has nowhere to go. */
@keyframes sheet-in { from { opacity: 0; transform: translateY(var(--space-3)); } }
@media (max-width: 1100px) {
  .menu-button { display: grid; }
  .top-menu {
    display: none; position: fixed; inset: 0; z-index: 40;
    grid-template-rows: minmax(0, 1fr) auto; align-content: start;
    padding: calc(var(--space-6) + var(--space-16) + var(--space-8)) var(--hh-gutter) var(--space-8);
    overflow-y: auto; overscroll-behavior: contain;
    background: var(--background); font-family: var(--font-sans); color: var(--hh-text);
  }
  .top.menu-open .top-menu { display: grid; animation: sheet-in 220ms cubic-bezier(.2, .8, .2, 1); }
  /* The header's own plate goes under the panel; its two corners stay on top of it. */
  .top.menu-open .brand, .top.menu-open .menu-button { position: relative; z-index: 41; }
  /* One thing scrolls while it is open, and it is the panel. */
  :root:has(.top.menu-open) body { overflow: hidden; }
  .top-nav { display: grid; align-content: start; gap: 0; font-family: var(--font-display); font-size: var(--text-3xl); font-weight: var(--weight-medium); letter-spacing: var(--tracking-display); line-height: 1.1; }
  .top-nav a { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); padding: var(--space-5) 0; border-bottom: 1px solid var(--hh-line); color: var(--hh-text); transition: color var(--hh-ease), opacity var(--hh-ease); }
  .top-nav a:hover, .top-nav a:focus-visible { outline: 0; opacity: .7; }
  .top-nav .i { width: var(--space-6); height: var(--space-6); color: var(--hh-text-dim); stroke-width: 1.5; }
  .top-nav a[aria-current], .top-nav a[aria-current] .i { color: var(--hh-accent-legible); }
  .top-tools { flex-wrap: wrap; justify-content: space-between; gap: var(--space-3); padding-top: var(--space-8); }
  /* The panel has the room the row did not: the sign-in reads as a word again, at the size of the page's buttons. */
  .top-menu #sign-in-button .label { display: inline; }
  .top-menu #sign-in-button { width: auto; height: var(--hh-field); padding: 0 var(--space-5); border-radius: var(--radius-lg); font-size: var(--text-base); }
  .top-menu .appearance > button, .top-menu .account-mark { width: var(--hh-field); height: var(--hh-field); }
  /* The two controls' popovers unfold inside the panel, on a full row under the controls. */
  .top-menu .appearance, .top-menu .account { display: contents; }
  .top-menu .menu { position: static; order: 3; flex-basis: 100%; width: auto; margin-top: var(--space-2); padding: var(--space-4) 0 0; background: none; border: 0; border-top: 1px solid var(--hh-line); border-radius: 0; box-shadow: none; animation: none; -webkit-backdrop-filter: none; backdrop-filter: none; }
}
}

/* ---- theme switch */
.appearance { position: relative; }
.appearance > button { display: grid; place-items: center; width: var(--hh-control); height: var(--hh-control); border-radius: 50%; border: 1px solid var(--hh-line-strong); color: var(--hh-text); transition: border-color var(--hh-ease), transform var(--hh-ease); }
.appearance > button:hover, .appearance > button[aria-expanded="true"] { border-color: var(--hh-line-focus); }
.appearance > button:active { transform: scale(.94); }
.appearance > button .i { width: var(--hh-icon-small); height: var(--hh-icon-small); }
.appearance > button .i[data-for] { display: none; }
:root[data-theme="dark"] .appearance > button .i[data-for="dark"],
:root[data-theme="light"] .appearance > button .i[data-for="light"],
:root[data-theme="immersive"] .appearance > button .i[data-for="immersive"] { display: block; }
.menu {
  position: absolute; right: 0; top: calc(100% + var(--space-3)); z-index: 40; width: min(16.25rem, calc(100vw - 2 * var(--hh-gutter))); padding: var(--space-1);
  background: var(--hh-popover); border: 1px solid var(--hh-line-strong); border-radius: var(--radius-lg);
  box-shadow: 0 var(--space-4) var(--space-12) var(--hh-shadow);
  font-family: var(--font-sans); font-size: var(--text-sm); color: var(--hh-text);
  transform-origin: top right; animation: menu-in 160ms cubic-bezier(.2, .8, .2, 1);
}
@keyframes menu-in { from { opacity: 0; transform: translateY(calc(-1 * var(--space-1))) scale(.97); } }
.menu [role="menuitemradio"] { display: flex; align-items: center; gap: var(--space-3); width: 100%; height: var(--hh-control); padding: 0 var(--space-3); border-radius: var(--radius-md); text-align: left; transition: background var(--hh-ease); }
.menu [role="menuitemradio"]:hover, .menu [role="menuitemradio"]:focus-visible { background: var(--hh-fill); outline: 0; }
.menu [role="menuitemradio"] .label { flex: 1; }
.menu [role="menuitemradio"] .i { color: var(--hh-text-dim); }
.menu [role="menuitemradio"] .tick { visibility: hidden; color: var(--hh-text); }
.menu [role="menuitemradio"][aria-checked="true"] { background: var(--hh-fill); }
.menu [role="menuitemradio"][aria-checked="true"] .i { color: var(--hh-text); }
.menu [role="menuitemradio"][aria-checked="true"] .tick { visibility: visible; }
.walls { display: grid; gap: var(--space-2); margin-top: var(--space-1); padding: var(--space-3) var(--space-2) var(--space-2); border-top: 1px solid var(--hh-line); }
.walls h3 { margin: 0; font-size: var(--text-sm); font-weight: var(--weight-normal); color: var(--hh-text-dim); padding: 0 var(--space-1); }
.wall-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-2); }
.wall { position: relative; aspect-ratio: 1.618; border-radius: var(--radius-md); overflow: hidden; outline: 1px solid var(--hh-line-strong); outline-offset: 0; transition: outline-color var(--hh-ease), transform var(--hh-ease); }
.wall img { width: 100%; height: 100%; object-fit: cover; display: block; }
.wall:hover { transform: translateY(-1px); outline-color: var(--hh-line-focus); }
.wall[aria-checked="true"] { outline: 2px solid var(--hh-text); outline-offset: 2px; }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: 280ms; }

/* ---- sign-in (src/auth.js)
   The control sits at the end of the header cluster. Signed out it is a word; signed in it is the person's own
   mark, the same circle as the theme control beside it, so the row keeps its rhythm either way. The sheet it
   opens borrows the popover, the field and the buttons the rest of the site already uses. Every value resolves
   to the Hologram brand kit. */
.account { position: relative; display: flex; align-items: center; }

/* The one brand-coloured control on the page: the only thing here asking to be done. */
.sign-in {
  display: inline-flex; align-items: center; gap: var(--space-2);
  height: var(--hh-control); padding: 0 var(--space-4);
  background: var(--hh-accent); border: 1px solid var(--hh-accent); border-radius: var(--radius-lg);
  font-family: var(--font-sans); font-size: var(--hh-ui); font-weight: var(--weight-semibold);
  color: var(--hh-accent-text); white-space: nowrap;
  transition: opacity var(--hh-ease), transform var(--hh-ease);
}
.sign-in:hover { opacity: .88; }
.sign-in:active { transform: scale(.97); }
.sign-in .i { width: var(--hh-icon-small); height: var(--hh-icon-small); color: var(--hh-accent-text); stroke-width: 2; }

/* Which of the two controls shows is decided before the first paint, from the hint in storage, so a signed-in
   person never sees "Sign in" flash on the way to their own mark. The letter rides in on a custom property for
   the same reason; chrome.js keeps both in step once it has the real session. */
:root { --hh-account-initial: ""; }
#account-button { display: none; }
#account-initial::before { content: var(--hh-account-initial); }
:root[data-account="in"] #sign-in-button { display: none; }
:root[data-account="in"] #account-button { display: grid; }

/* Signed in: the same circle the Sign in control was, still wearing the brand colour, now carrying one letter —
   or the person's own picture when the provider they used gave us one. */
.account-mark {
  display: grid; place-items: center; overflow: hidden;
  width: var(--hh-control); height: var(--hh-control);
  border: 1px solid var(--hh-accent); border-radius: 50%;
  background: var(--hh-accent);
  font-family: var(--font-sans); font-size: var(--text-sm); font-weight: var(--weight-semibold);
  color: var(--hh-accent-text);
  transition: border-color var(--hh-ease), transform var(--hh-ease), opacity var(--hh-ease);
}
.account-mark:hover { opacity: .88; }
.account-mark img { grid-area: 1 / 1; width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }
/* With a picture the letter underneath it is not needed, and the brand ground stops being a background. */
.account-mark.has-photo { background: var(--hh-fill); border-color: var(--hh-line-strong); }
.account-mark.has-photo #account-initial { display: none; }
.account-mark:hover, .account-mark[aria-expanded="true"] { border-color: var(--hh-line-focus); }
.account-mark:active { transform: scale(.94); }

.account .menu { font-family: var(--font-sans); }
.account-who { display: grid; gap: var(--space-1); padding: var(--space-3); }
.account-who .label { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--hh-text-faint); }
.account-who b { font-weight: var(--weight-medium); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.account-rows { padding-top: var(--space-1); border-top: 1px solid var(--hh-line); }
.account-row {
  display: flex; align-items: center; gap: var(--space-3); width: 100%;
  min-height: var(--hh-field); padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md); text-align: left;
  transition: background var(--hh-ease);
}
button.account-row:hover, button.account-row:focus-visible { background: var(--hh-fill); outline: 0; }
.account-row .i { color: var(--hh-text-dim); }
.account-row .label { flex: 1; display: grid; min-width: 0; }
.account-row .sub { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--hh-text-dim); overflow: hidden; text-overflow: ellipsis; }
.account-row.quiet { color: var(--hh-text-dim); }

.auth-sheet {
  width: min(25rem, calc(100vw - 2 * var(--hh-gutter))); padding: var(--space-8);
  background: var(--hh-popover); color: var(--hh-text);
  border: 1px solid var(--hh-line-strong); border-radius: var(--radius-xl);
  box-shadow: 0 var(--space-4) var(--space-12) var(--hh-shadow);
  font-family: var(--font-sans); font-size: var(--text-base);
}
.auth-sheet::backdrop { background: var(--hh-shadow); backdrop-filter: blur(var(--space-1)); }
.auth-sheet[open] { animation: menu-in 200ms cubic-bezier(.2, .8, .2, 1); }
.auth-close { position: absolute; top: var(--space-4); right: var(--space-4); }
.auth-close button { display: grid; place-items: center; width: var(--hh-control); height: var(--hh-control); border-radius: var(--radius-md); color: var(--hh-text-dim); transition: background var(--hh-ease), color var(--hh-ease); }
.auth-close button:hover { background: var(--hh-fill); color: var(--hh-text); }
.auth-head { display: grid; gap: var(--space-2); margin-bottom: var(--space-6); padding-right: var(--space-10); }
.auth-head h2 { font-family: var(--font-display); font-size: var(--text-3xl); font-weight: var(--weight-medium); letter-spacing: var(--tracking-display); line-height: 1.2; }
.auth-head p { font-size: var(--text-base); line-height: var(--hh-leading); color: var(--hh-text-dim); }
.auth-body { display: grid; gap: var(--space-5); }
.auth-foot { margin-top: var(--space-6); padding-top: var(--space-4); border-top: 1px solid var(--hh-line); font-size: var(--text-sm); line-height: var(--hh-leading); color: var(--hh-text-dim); }
.auth-error { font-size: var(--text-sm); line-height: var(--hh-leading); color: var(--hh-bad); }

/* Typing a six digit code is one task. The other ways in step out of the way while it is on screen. */
.auth-sheet.on-code .providers, .auth-sheet.on-code .or, .auth-sheet.on-code .auth-head p { display: none; }
.providers { display: grid; gap: var(--space-3); }
.provider {
  display: flex; align-items: center; justify-content: center; gap: var(--space-3);
  height: var(--hh-field); padding: 0 var(--space-4);
  border: 1px solid var(--hh-line-strong); border-radius: var(--radius-md);
  font-size: var(--text-base); font-weight: var(--weight-medium);
  transition: border-color var(--hh-ease), background var(--hh-ease);
}
.provider:hover { border-color: var(--hh-line-focus); background: var(--hh-wash); }
.provider .mark { width: var(--space-5); height: var(--space-5); }
/* The way in that worked last time, offered first. */
.provider.preferred { border-color: var(--hh-line-focus); background: var(--hh-fill); }
.or { display: flex; align-items: center; gap: var(--space-4); font-size: var(--text-sm); color: var(--hh-text-dim); }
.or::before, .or::after { content: ""; flex: 1; height: 1px; background: var(--hh-line); }
.email-step, .code-step { display: grid; gap: var(--space-3); }
.email-step .button, .code-step .button { justify-content: center; font-size: var(--text-base); font-weight: var(--weight-medium); }
.code-sent { font-size: var(--text-base); line-height: var(--hh-leading); color: var(--hh-text-dim); }
.code-step .field input { font-family: var(--font-mono); font-size: var(--text-2xl); letter-spacing: var(--tracking-caps); text-align: center; }
.code-foot { display: flex; justify-content: space-between; gap: var(--space-4); font-size: var(--text-sm); }
.code-foot .link { color: var(--hh-text-dim); }
.code-foot .link:hover { color: var(--hh-text); }

/* ---- immersive: the wallpaper under everything, glass over it */
:root[data-wallpaper="alps"] { --hh-wallpaper: url("wallpapers/alps.jpg"); }
:root[data-wallpaper="galaxy"] { --hh-wallpaper: url("wallpapers/galaxy.jpg"); }
:root[data-wallpaper="aurora"] { --hh-wallpaper: url("wallpapers/aurora.jpg"); }
:root[data-theme="immersive"] {
  --hh-ground: transparent;
  --hh-surface: color-mix(in srgb, var(--card) 86%, transparent);
  --hh-popover: var(--popover);
  --hh-fill: color-mix(in srgb, var(--muted) 84%, transparent);
  --hh-glass: blur(var(--space-6)) saturate(1.3);
  /* How much ground is laid over the wallpaper. qa/contrast.js reads it, so a page may ask for more. */
  --hh-veil: 22%;
}
:root[data-theme="immersive"] { background: var(--background); }
:root[data-theme="immersive"] body { background: transparent; }
:root[data-theme="immersive"] body::before {
  content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background: linear-gradient(color-mix(in srgb, var(--background) var(--hh-veil), transparent), color-mix(in srgb, var(--background) var(--hh-veil), transparent)), var(--hh-wallpaper) center / cover no-repeat, var(--background);
}
:root[data-theme="immersive"] .panel,
:root[data-theme="immersive"] .menu,
:root[data-theme="immersive"] .sort [role="listbox"],
:root[data-theme="immersive"] .sheet-footer { -webkit-backdrop-filter: var(--hh-glass); backdrop-filter: var(--hh-glass); }
/* Over a photograph the header draws no plate, on every page, as the landing has always done: the row sits
   on the picture and its words take a shadow instead, which costs the picture nothing. On the pages that
   scroll, the veil above the row is what keeps content from colliding with it. */
:root[data-theme="immersive"] .top { background: none; }
:root[data-theme="immersive"] .top .brand, :root[data-theme="immersive"] .top-end, :root[data-theme="immersive"] .top-nav { text-shadow: 0 var(--space-1) var(--space-4) color-mix(in srgb, var(--background) 80%, transparent); }
@media (max-width: 1100px) {
  :root[data-theme="immersive"] .top-menu { background: color-mix(in srgb, var(--background) 78%, transparent); -webkit-backdrop-filter: var(--hh-glass); backdrop-filter: var(--hh-glass); }
}
:root[data-theme="immersive"] .veil {
  background: color-mix(in srgb, var(--background) 35%, transparent);
  -webkit-backdrop-filter: blur(var(--space-4)); backdrop-filter: blur(var(--space-4));
}

/* ---- the mesh behind every catalogue card (Models, Registry, Spaces) --------------------------------
   Fixed in CSS pixels on purpose: the box is 260x200 and src/card-art.mjs draws a 260x200 viewBox, so
   one unit is one pixel and the facets are the same size on all three pages, whatever the card height
   or the column count. A shorter card clips the bottom. Change one number and you change both files. */
.card { position: relative; overflow: hidden; isolation: isolate; }
.art {
  position: absolute; z-index: -1; top: 0; right: 0; width: min(55%, var(--hh-art-w)); height: var(--hh-art-h);
  pointer-events: none; opacity: .85;
  -webkit-mask-image: linear-gradient(90deg, transparent, var(--hh-text) var(--space-16));
  mask-image: linear-gradient(90deg, transparent, var(--hh-text) var(--space-16));
  transition: opacity var(--hh-ease);
}
.art .facets { fill: var(--hh-text); }
.art .edges { fill: none; stroke: var(--hh-text); stroke-width: .5; opacity: .14; }
.card:hover .art { opacity: 1; }
