/* Hapi Homes admin — warm, calm, readable. One palette, defined once. */
:root {
  --bg: #f3ecdd;
  --panel: #fbf7ec;
  --panel-2: #f6efe0;
  --ink: #3d3428;
  --ink-soft: #75674f;
  --line: #e2d6bd;
  --accent: #8a6d3b;
  --accent-ink: #fffdf6;
  --ok: #4c7a58;
  --ok-bg: #e6efe6;
  --warn: #96700f;
  --warn-bg: #f7ecce;
  --err: #a4432e;
  --err-bg: #f6e2dc;
}
* { box-sizing: border-box; }
body {
  margin: 0; background: var(--bg); color: var(--ink);
  font: 15px/1.55 "Segoe UI", system-ui, sans-serif;
}
h1, h2, h3 { font-family: Georgia, "Times New Roman", serif; font-weight: normal; color: var(--ink); }
h1 { font-size: 26px; margin: 0 0 4px; }
h2 { font-size: 20px; margin: 26px 0 10px; }
a { color: var(--accent); }
header.top {
  background: var(--panel); border-bottom: 1px solid var(--line);
  display: flex; align-items: center; gap: 24px; padding: 12px 28px;
}
header.top .brand { font-family: Georgia, serif; font-size: 19px; letter-spacing: .4px; text-decoration: none; color: var(--ink); }
header.top nav { display: flex; gap: 18px; }
header.top nav a { text-decoration: none; color: var(--ink-soft); padding: 4px 2px; }
header.top nav a:hover { color: var(--accent); }
header.top form { margin-left: 14px; }
/* Who is signed in, and with what authority. The local part of the address
   only - the full email is not the header's business. */
.whoami { margin-left: auto; display: flex; align-items: center; gap: 8px; line-height: 1; }
.whoami-name { font-weight: 600; font-size: 14px; color: var(--ink); }
.whoami-role {
  font-size: 11.5px; text-transform: uppercase; letter-spacing: .07em; font-weight: 600;
  color: var(--accent); background: var(--panel-2);
  border: 1px solid var(--line); border-radius: 20px; padding: 3px 10px;
}
main { max-width: 1240px; margin: 28px auto 80px; padding: 0 24px; }
.nowrap { white-space: nowrap; }
.card {
  background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
  padding: 20px 24px; margin-bottom: 20px;
}
table { border-collapse: collapse; width: 100%; }
th { text-align: left; color: var(--ink-soft); font-weight: 600; font-size: 12.5px;
     text-transform: uppercase; letter-spacing: .5px; padding: 7px 10px; border-bottom: 2px solid var(--line); }
td { padding: 7px 10px; border-bottom: 1px solid var(--line); vertical-align: middle; }
tr:last-child td { border-bottom: none; }
tr:hover td { background: var(--panel-2); }
input[type=text], input[type=number], input[type=email], input[type=password], textarea, select {
  background: #fffdf6; border: 1px solid var(--line); border-radius: 6px;
  padding: 8px 10px; font: inherit; color: var(--ink); width: 100%;
}
input:focus, textarea:focus, select:focus { outline: 2px solid var(--accent); outline-offset: 0; border-color: var(--accent); }
label { display: block; font-size: 13px; color: var(--ink-soft); margin: 12px 0 4px; }
.row { display: flex; gap: 16px; flex-wrap: wrap; }
.row > div { flex: 1; min-width: 140px; }
button, .btn {
  background: var(--accent); color: var(--accent-ink); border: none; border-radius: 6px;
  padding: 9px 18px; font: inherit; cursor: pointer; text-decoration: none; display: inline-block;
}
button:hover, .btn:hover { filter: brightness(1.08); }
button.quiet, .btn.quiet { background: transparent; color: var(--accent); border: 1px solid var(--line); }
button.danger { background: var(--err); }
button.small { padding: 4px 10px; font-size: 13px; }
.badge { display: inline-block; border-radius: 20px; padding: 2px 12px; font-size: 12.5px; font-weight: 600; }
.badge.ok   { background: var(--ok-bg);   color: var(--ok); }
.badge.warn { background: var(--warn-bg); color: var(--warn); }
.badge.err  { background: var(--err-bg);  color: var(--err); }
.badge.off  { background: var(--panel-2); color: var(--ink-soft); border: 1px solid var(--line); }
.findings { list-style: none; padding: 0; margin: 0; }
.findings li { padding: 10px 14px; border-radius: 8px; margin-bottom: 8px; font-size: 14px; }
.findings li.ERROR { background: var(--err-bg); color: #7c2f1e; border-left: 4px solid var(--err); }
.findings li.WARN  { background: var(--warn-bg); color: #6d520c; border-left: 4px solid var(--warn); }
.findings li code { background: rgba(0,0,0,.05); padding: 1px 5px; border-radius: 4px; }
.surface-label { font-weight: 600; }
.muted { color: var(--ink-soft); font-size: 13.5px; }
.thumb { width: 44px; height: 44px; border-radius: 6px; border: 1px solid var(--line); object-fit: cover; display: block; }
.thumb-btn {
  background: none; border: none; padding: 0; cursor: zoom-in; border-radius: 6px; line-height: 0;
}
.thumb-btn:hover .thumb { outline: 2px solid var(--accent); outline-offset: 1px; }
.thumb-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Material image viewer */
#matview {
  position: fixed; inset: 0; z-index: 980; background: rgba(43, 36, 24, .78);
  display: none; align-items: center; justify-content: center; gap: 8px; padding: 32px 16px;
}
#matview.open { display: flex; }
#matview .mv-figure {
  margin: 0; background: var(--panel); border: 1px solid var(--line); border-radius: 12px;
  padding: 16px; max-width: min(720px, 90vw); display: flex; flex-direction: column; gap: 12px;
  flex: 0 0 auto;
}
#matview img {
  /* clamp, not a bare vw: a narrow window still gets a usable image instead
     of a collapsed sliver. */
  width: clamp(240px, 74vw, 520px); height: auto; aspect-ratio: 1 / 1; object-fit: cover;
  border-radius: 8px; border: 1px solid var(--line); background: var(--panel-2);
}
#matview .mv-nav { flex: 0 0 auto; }
#matview figcaption { display: flex; flex-direction: column; gap: 3px; text-align: center; }
#matview figcaption strong { font-size: 17px; font-family: Georgia, serif; font-weight: normal; }
#matview figcaption .muted { font-size: 13px; font-variant-numeric: tabular-nums; }
#matview .mv-nav, #matview .mv-close {
  background: var(--panel); color: var(--ink); border: 1px solid var(--line);
  border-radius: 50%; width: 42px; height: 42px; font-size: 22px; line-height: 1; cursor: pointer;
}
#matview .mv-nav:hover, #matview .mv-close:hover { background: var(--panel-2); color: var(--accent); }
#matview .mv-close { position: absolute; top: 20px; right: 22px; font-size: 24px; }
.tabchip {
  display: inline-flex; align-items: center; gap: 6px; background: var(--panel-2);
  border: 1px solid var(--line); border-radius: 16px; padding: 2px 6px 2px 12px; margin: 2px 4px 2px 0; font-size: 13px;
}
.tabchip form { display: inline; margin: 0; }
.tabchip button { background: none; border: none; color: var(--err); cursor: pointer; padding: 0 4px; font-size: 15px; }
.inline-form { display: flex; gap: 8px; align-items: center; margin-top: 6px; }
.inline-form select { width: auto; }
.inline-form input[type=text] { width: 150px; }
.login-wrap { max-width: 380px; margin: 12vh auto; }
.toast {
  position: fixed; top: 18px; left: 50%; transform: translateX(-50%); z-index: 1000;
  padding: 11px 22px; border-radius: 10px; font-size: 14.5px; font-weight: 600;
  box-shadow: 0 6px 24px rgba(61, 52, 40, .18);
  animation: toast-fade 3s ease forwards; pointer-events: none; max-width: 80vw;
  display: flex; align-items: center; gap: 14px;
}
/* A toast carrying an Undo must stay long enough to click, and be clickable. */
.toast.with-action { animation-duration: 10s; pointer-events: auto; }
.toast form { margin: 0; }
.toast button {
  background: var(--ok); color: var(--panel); border: none; border-radius: 6px;
  padding: 4px 14px; font: 600 13.5px inherit; cursor: pointer;
}
.toast button:hover { filter: brightness(1.1); }
.toast.ok  { background: var(--ok-bg);  color: var(--ok);  border: 1px solid var(--ok); }
.toast.err { background: var(--err-bg); color: var(--err); border: 1px solid var(--err); }
@keyframes toast-fade {
  0% { opacity: 0; transform: translate(-50%, -8px); }
  8% { opacity: 1; transform: translate(-50%, 0); }
  80% { opacity: 1; }
  100% { opacity: 0; visibility: hidden; }
}
@media (prefers-reduced-motion: reduce) { .toast { animation: none; } }

/* ---- Houses grid ---- */
.page-head { display: flex; align-items: flex-start; gap: 24px; margin-bottom: 22px; }
.page-head > div { flex: 1; }
.page-head h1 { margin-bottom: 6px; }
.page-head .muted { max-width: 62ch; }
.page-head .btn { margin-top: 6px; white-space: nowrap; }

.house-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(310px, 1fr)); gap: 24px; }
.hcard {
  background: var(--panel); border: 1px solid var(--line); border-radius: 12px;
  overflow: hidden; display: flex; flex-direction: column;
  transition: box-shadow .2s ease, transform .2s ease;
}
.hcard:hover { box-shadow: 0 10px 26px rgba(61, 52, 40, .14); transform: translateY(-2px); }

.hcard-media { position: relative; aspect-ratio: 4 / 3; overflow: hidden; background: var(--panel-2); }
.hcard-media img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transition: opacity .25s ease, transform .5s ease;
}
.hcard-media img.active { opacity: 1; }
.hcard:hover .hcard-media img.active { transform: scale(1.06); }
.hcard-empty {
  position: absolute; inset: 0; display: flex; flex-direction: column; gap: 4px;
  align-items: center; justify-content: center; color: var(--ink-soft); font-size: 14px;
  background: repeating-linear-gradient(45deg, var(--panel-2), var(--panel-2) 12px, var(--panel) 12px, var(--panel) 24px);
}
.hcard-empty span { font-size: 12px; opacity: .8; }

/* The disc is a button, so it inherits the generic button padding (9px 18px).
   Against a 34px box that horizontal padding alone was wider than the circle,
   which is what pushed the arrow off centre. Padding is zeroed and the icon is
   centred as a flex child instead. */
.hnav {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
  display: flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; padding: 0;
  border-radius: 50%; border: none; cursor: pointer;
  background: rgba(251, 247, 236, .92); color: var(--ink);
  opacity: 0; transition: opacity .18s ease; box-shadow: 0 2px 8px rgba(0, 0, 0, .18);
}
/* Drawn rather than typed: a ‹ character sits on a baseline and carries its own
   side bearings, so it cannot be relied on to land in the middle of a circle. */
.hnav svg { width: 22px; height: 22px; display: block; }
.hnav.prev { left: 10px; } .hnav.next { right: 10px; }
.hcard:hover .hnav, .hnav:focus-visible { opacity: 1; }
.hnav:hover { color: var(--accent); }

.hdots { position: absolute; bottom: 10px; left: 50%; transform: translateX(-50%); display: flex; gap: 5px; z-index: 2; }
.hdots span { width: 6px; height: 6px; border-radius: 50%; background: rgba(251, 247, 236, .55); }
.hdots span.on { background: var(--accent-ink); box-shadow: 0 0 0 1px rgba(0, 0, 0, .18); }
.hcard-tag { position: absolute; top: 10px; left: 10px; z-index: 2; }

.hcard-body { padding: 14px 18px 4px; flex: 1; }
.hcard-body h3 { margin: 0 0 2px; font-size: 19px; }
.hcard-body h3 a { text-decoration: none; color: var(--ink); }
.hcard-body h3 a:hover { color: var(--accent); }
.hslug { margin: 0 0 10px; font-size: 13px; }
.hstats { display: flex; flex-wrap: wrap; gap: 6px 16px; align-items: center; font-size: 13.5px; color: var(--ink-soft); }
.hstats strong { color: var(--ink); font-variant-numeric: tabular-nums; }
.hmeta { margin: 10px 0 0; font-size: 12.5px; }
/* One row, equal-width buttons — four fit side by side (Open / Draft /
   Customer / HDRP) without wrapping. */
.hcard-actions { display: flex; gap: 8px; padding: 14px 18px 18px; }
.hcard-actions .btn {
  flex: 1 1 0; min-width: 0; padding: 7px 4px; font-size: 13.5px;
  text-align: center; white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
  .hcard, .hcard-media img { transition: none; }
  .hcard:hover { transform: none; }
  .hcard:hover .hcard-media img.active { transform: none; }
}

/* Collapsible cards (house editor sections) */
details.card { padding: 0; }
details.card > summary {
  list-style: none; cursor: pointer; padding: 16px 24px; user-select: none;
  display: flex; align-items: center; gap: 10px;
}
details.card > summary::-webkit-details-marker { display: none; }
details.card > summary::before {
  content: "▸"; color: var(--accent); font-size: 13px; transition: transform .15s;
}
details.card[open] > summary::before { transform: rotate(90deg); }
details.card > summary h2 { margin: 0; padding: 0; border: none; font-size: 20px; }
details.card > summary .count { margin-left: auto; }
details.card > .card-body { padding: 0 24px 20px; }

/* Pending-changes log */
.pending-list { list-style: none; margin: 0; padding: 0; font-size: 14px; }
.pending-list li { display: flex; gap: 12px; padding: 7px 2px; border-bottom: 1px dashed var(--line); }
.pending-list li:last-child { border-bottom: none; }
.pending-list .pwhen { color: var(--ink-soft); white-space: nowrap; font-variant-numeric: tabular-nums; }
.pending-list .pwho { color: var(--accent); white-space: nowrap; font-weight: 600; }
.pending-list .ptext { flex: 1; }
.pending-list .prevert { margin-left: auto; white-space: nowrap; display: flex; gap: 6px; align-items: center; }
.pending-list form { margin: 0; }
button.ghost { background: transparent; color: var(--ink-soft); border: 1px solid transparent; }
button.ghost:hover { color: var(--err); border-color: var(--line); filter: none; }

/* Deep links to a surface still land clear of the header. Attach/detach no
   longer scroll at all — the row flashes instead, so you keep your place. */
[id^="surf-"] { scroll-margin-top: 90px; }
.srf-row--changed { animation: srf-flash 1.6s ease both; }
@keyframes srf-flash {
  0%, 55% { background: var(--warn-bg); box-shadow: inset 3px 0 0 var(--accent); }
  100% { background: transparent; box-shadow: inset 3px 0 0 transparent; }
}
@media (prefers-reduced-motion: reduce) { .srf-row--changed { animation: none; background: var(--warn-bg); } }

/* Surface code chips */
.gocode {
  font-family: Consolas, monospace; font-size: 12px; background: var(--panel-2);
  border: 1px solid var(--line); border-radius: 5px; padding: 1px 7px; color: var(--ink-soft);
  white-space: nowrap;
}

/* Surface map overlay */
#surfmap-btn {
  position: fixed; right: 22px; bottom: 22px; z-index: 900;
  background: var(--accent); color: var(--accent-ink); border: none; border-radius: 99px;
  padding: 12px 20px; font: 600 14.5px "Segoe UI", system-ui, sans-serif; cursor: pointer;
  box-shadow: 0 5px 18px rgba(61,52,40,.3);
}
#surfmap-btn:hover { filter: brightness(1.08); }
#surfmap { position: fixed; inset: 0; z-index: 950; background: rgba(43,36,24,.62);
  display: none; align-items: center; justify-content: center; padding: 24px; }
#surfmap.open { display: flex; }
#surfmap .panel {
  background: var(--panel); border: 1px solid var(--line); border-radius: 12px;
  max-width: min(1100px, 96vw); max-height: 92vh; overflow: auto; padding: 18px 24px; width: 100%;
}
#surfmap .areas-nav { display: flex; gap: 8px; flex-wrap: wrap; margin: 8px 0 14px; }
#surfmap .areas-nav button {
  background: var(--panel-2); color: var(--ink); border: 1px solid var(--line);
  border-radius: 16px; padding: 4px 14px; font-size: 13px;
}
#surfmap .areas-nav button.active { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
#surfmap .map-pane { display: none; }
#surfmap .map-pane.active { display: flex; gap: 18px; flex-wrap: wrap; }
#surfmap .map-img { flex: 2 1 480px; min-width: 320px; }
#surfmap .map-img img { width: 100%; border-radius: 8px; border: 1px solid var(--line); background: #00000010; }
#surfmap .map-list { flex: 1 1 240px; min-width: 220px; }
#surfmap .map-list li { margin: 6px 0; }
#surfmap .surf-item[data-shot] { cursor: pointer; border-radius: 6px; padding: 4px 6px; }
#surfmap .surf-item[data-shot]:hover { background: var(--panel-2); }
#surfmap .surf-item.active { background: var(--panel-2); outline: 2px solid var(--accent); }
#surfmap .surf-item.dim { opacity: .45; }
#surfmap .noimg { border: 2px dashed var(--line); border-radius: 8px; padding: 34px 18px;
  text-align: center; color: var(--ink-soft); font-size: 14px; }
#surfmap .close { float: right; background: none; border: none; color: var(--ink-soft); font-size: 24px; cursor: pointer; }
.flash-note { background: var(--ok-bg); color: var(--ok); border-radius: 8px; padding: 10px 16px; margin-bottom: 16px; }
.area-block { margin-bottom: 4px; }
.area-block h3 { margin: 18px 0 6px; font-size: 17px; color: var(--accent); }
/* Collapsible area sections on the house editor */
details.area-block { border: 1px solid var(--line); border-radius: 8px; margin-bottom: 10px; background: var(--panel-2); }
details.area-block > summary {
  list-style: none; cursor: pointer; user-select: none;
  display: flex; align-items: center; gap: 10px; padding: 10px 16px;
}
details.area-block > summary::-webkit-details-marker { display: none; }
details.area-block > summary:hover { background: var(--panel); }
details.area-block > summary h3 { margin: 0; }
details.area-block > summary .count { margin-left: auto; font-size: 13px; }
.area-chev { color: var(--accent); font-size: 13px; transition: transform .15s; flex: 0 0 auto; }
details.area-block[open] .area-chev { transform: rotate(90deg); }
details.area-block > .srf-list, details.area-block > p { margin: 0 16px 12px; }
details.area-block > .srf-list { background: var(--panel); border-radius: 0 0 8px 8px; border-top: none; }
@media (prefers-reduced-motion: reduce) { .area-chev { transition: none; } }
.kv { display: grid; grid-template-columns: 180px 1fr; gap: 4px 16px; font-size: 14px; }
.kv dt { color: var(--ink-soft); }
.kv dd { margin: 0; word-break: break-all; }

/* ---- Materials: menu-to-grid ---- */
:root {
  --mtg-img: clamp(44px, 5vw, 72px);
  --mtg-img-lg: clamp(96px, 13vw, 176px);
  --mtg-gap: clamp(8px, 1vw, 14px);
  --mtg-gap-lg: clamp(14px, 2vw, 26px);
  --mtg-ease: cubic-bezier(.215, .61, .355, 1);   /* power3-out */
  --mtg-ease-expo: cubic-bezier(.16, 1, .3, 1);   /* expo-out */
}
.mtg { border-bottom: 1px solid var(--line); margin-top: 4px; }
.mtg-row {
  display: grid; grid-template-columns: auto 1fr auto; align-items: center;
  gap: 0 clamp(16px, 5vw, 60px);
  padding: clamp(10px, 1.2vw, 18px) clamp(8px, 2vw, 24px);
  border-top: 1px solid var(--line); cursor: pointer;
  transition: background-color .3s ease-out;
}
.mtg-row:hover, .mtg-row:focus-visible { background-color: var(--panel); outline: none; }
.mtg-row:focus-visible { box-shadow: inset 0 0 0 2px var(--accent); }

.mtg-cell--text {
  position: relative;
  /* Space the stats line occupies even while hidden, so the row never changes
     height on hover. The title is parked half of it lower, which centres it
     optically at rest and lets it rise as the stats fade in. */
  --sub-space: 30px;
}
/* The clamped size lives HERE, on the element whose em units the padding and
   fill resolve against. It previously sat on the inner span while the box was
   sized in em against the parent's 20px, so at real viewport widths the text
   grew past its container and the names were cut in half. */
.mtg-title {
  margin: 0; white-space: nowrap;
  font-size: clamp(1.5rem, 3.2vw, 2.6rem); line-height: 1.15;
  transform: translateY(calc(var(--sub-space) / 2));
  transition: transform .45s cubic-bezier(.2, 1, .8, 1);
}
.mtg-row:hover .mtg-title,
.mtg-row:focus-visible .mtg-title { transform: translateY(0); }
/* Nothing here clips: no fixed height, no overflow hidden. Whatever size the
   clamp resolves to, the full name renders. */
.mtg-title__wrap {
  position: relative; display: inline-block; padding: .14em .8em; isolation: isolate;
}
/* Hover fill in the spirit of Codrops' "anthe" button: the block sweeps in and
   its right edge folds to an arrow point, while the label nudges left. Ours
   starts collapsed rather than permanently filled — a solid bar behind every
   name in a 21-row list would read far too heavy. */
.mtg-title__wrap::before {
  content: ""; position: absolute; inset: 0; z-index: -1; background: var(--ink);
  clip-path: polygon(0% 0%, 0% 0%, 0% 50%, 0% 100%, 0% 100%);
  transition: clip-path .4s cubic-bezier(.2, 1, .8, 1);
}
.mtg-row:hover .mtg-title__wrap::before,
.mtg-row:focus-visible .mtg-title__wrap::before {
  clip-path: polygon(0% 0%, 75% 0%, 100% 50%, 75% 100%, 0% 100%);
}
.mtg-title__text {
  display: inline-block; position: relative; z-index: 1;
  font-family: Georgia, "Times New Roman", serif; color: var(--ink);
  transition: color .3s ease .05s, transform .4s cubic-bezier(.2, 1, .8, 1);
}
.mtg-row:hover .mtg-title__text,
.mtg-row:focus-visible .mtg-title__text {
  color: var(--bg); transform: translate3d(-10px, 0, 0);
}

.mtg-sub {
  margin: 12px 0 0; font-size: 12.5px; padding-left: .85em;
  height: 18px; line-height: 18px; white-space: nowrap;   /* == --sub-space - margin */
  opacity: 0; transform: translateY(5px);
  transition: opacity .35s ease .08s, transform .35s var(--mtg-ease) .08s;
}
.mtg-row:hover .mtg-sub,
.mtg-row:focus-visible .mtg-sub { opacity: 1; transform: none; }

.mtg-cell--images {
  display: grid; grid-auto-flow: column; grid-auto-columns: auto;
  gap: var(--mtg-gap); place-content: center end; margin-left: auto;
}
/* The reveal lives on the wrapper and the inspect-zoom on the inner tile, so
   the two transforms never fight each other. */
.mtg-img {
  width: var(--mtg-img); position: relative; z-index: 1;
  opacity: 0; transform: translateX(20%) scale(.8); will-change: transform, opacity;
  transition: opacity .4s var(--mtg-ease), transform .4s var(--mtg-ease);
  transition-delay: calc((var(--n) - 1 - var(--i)) * 35ms);
}
.mtg-row:hover .mtg-img,
.mtg-row:focus-visible .mtg-img { opacity: 1; transform: translateX(0) scale(1); }
.mtg-img span {
  display: block; width: 100%; aspect-ratio: 1; border-radius: calc(var(--mtg-gap) / 2);
  background-size: cover; background-position: 50%; border: 1px solid var(--line);
  transition: transform .35s var(--mtg-ease-expo), box-shadow .35s var(--mtg-ease-expo);
  transform-origin: center;
}
/* Hover a single swatch to inspect it: eases up to ~2x in place. */
.mtg-img:hover { z-index: 6; }
.mtg-img:hover span {
  transform: scale(2.1);
  box-shadow: 0 10px 26px rgba(61, 52, 40, .28);
  border-color: var(--accent);
}
/* The last tile grows leftward so an enlarged swatch never pushes past the
   right edge of the page. */
.mtg-img:last-child span { transform-origin: right center; }
.mtg-noimg { font-size: 13px; }
.mtg-edit { opacity: 0; transition: opacity .25s ease; }
.mtg-row:hover .mtg-edit, .mtg-edit:focus-visible { opacity: 1; }

/* Full-screen grid the row morphs into */
body.mtg-locked { overflow: hidden; }
.mtg-preview {
  position: fixed; inset: 0; z-index: 990; display: none;
  align-items: center; justify-content: center; padding: 4vh 4vw;
  background: var(--bg);
  background: color-mix(in srgb, var(--bg) 94%, transparent);
}
.mtg-preview.open { display: flex; }
.mtg-preview__inner { display: flex; flex-direction: column; align-items: center; gap: 18px; max-width: 1200px; width: 100%; }
.mtg-preview__title {
  margin: 0; font-family: Georgia, serif; font-weight: 700; color: var(--accent);
  font-size: clamp(1.6rem, 4.4vw, 3rem); line-height: 1;
  animation: mtg-title-in .5s var(--mtg-ease-expo) both;
}
.mtg-preview__meta { margin: 0; animation: mtg-title-in .5s var(--mtg-ease-expo) .06s both; }
@keyframes mtg-title-in { from { opacity: 0; transform: translateY(60%); } to { opacity: 1; transform: none; } }
.mtg-grid {
  display: grid; grid-template-columns: repeat(4, var(--mtg-img-lg));
  gap: var(--mtg-gap-lg); justify-content: center; margin: 6px 0 4px;
}
.mtg-gimg { width: var(--mtg-img-lg); will-change: transform; }
.mtg-gimg span {
  display: block; width: 100%; aspect-ratio: 1; border-radius: calc(var(--mtg-gap-lg) / 3);
  background-size: cover; background-position: 50%; border: 1px solid var(--line);
  box-shadow: 0 6px 20px rgba(61, 52, 40, .12);
}
.mtg-close {
  position: absolute; top: 18px; right: 22px; background: none; border: none;
  font-size: 26px; line-height: 1; color: var(--ink-soft); cursor: pointer; padding: 8px;
}
.mtg-close:hover { color: var(--accent); }
.mtg-preview.closing .mtg-preview__title,
.mtg-preview.closing .mtg-preview__meta,
.mtg-preview.closing .mtg-open { opacity: 0; transition: opacity .2s ease; }

@media (max-width: 780px) {
  .mtg-row { grid-template-columns: 1fr auto; }
  .mtg-cell--images { display: none; }
  .mtg-grid { grid-template-columns: repeat(2, var(--mtg-img-lg)); }
}
@media (prefers-reduced-motion: reduce) {
  .mtg-title, .mtg-title__text, .mtg-title__wrap::before, .mtg-img span, .mtg-gimg { transition: none !important; }
  .mtg-preview__title, .mtg-preview__meta { animation: none; }
}

/* ---- Page-to-page transitions ----
   Cross-document View Transitions: the browser snapshots the outgoing page and
   cross-fades it into the incoming one, so a normal server-rendered navigation
   feels continuous. No JavaScript, and nothing to undo in browsers that lack
   support — they simply navigate as before. */
@view-transition { navigation: auto; }

/* Naming the two regions keeps the chrome still while the content moves:
   the header holds its position and only the page body animates. */
header.top { view-transition-name: admin-header; }
main { view-transition-name: admin-main; }

::view-transition-group(admin-header) { animation-duration: .01s; }
::view-transition-old(root), ::view-transition-new(root) { animation: none; }

::view-transition-old(admin-main) { animation: page-out .16s ease both; }
::view-transition-new(admin-main) { animation: page-in .34s cubic-bezier(.2, 1, .8, 1) both; }

@keyframes page-out { to { opacity: 0; transform: translateY(-6px); } }
@keyframes page-in { from { opacity: 0; transform: translateY(10px); } }

/* Browsers without View Transitions still get the arrival half of the effect. */
@supports not (view-transition-name: none) {
  main { animation: page-in .34s cubic-bezier(.2, 1, .8, 1) both; }
}

@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; }
  @supports not (view-transition-name: none) { main { animation: none; } }
}

/* ---- Surfaces: a miniature of the Materials page, one per surface ---- */
.srf-list { border-top: 1px solid var(--line); }
.srf-row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto;
  grid-template-areas: "main images actions" "chips chips chips" "add add add";
  align-items: center; gap: 0 18px;
  padding: 10px 8px; border-bottom: 1px solid var(--line);
  transition: background-color .3s ease-out;
}
.srf-row:hover, .srf-row--adding { background: var(--panel-2); }

.srf-main { grid-area: main; display: flex; flex-direction: column; min-width: 0; }
.srf-title {
  font-family: Georgia, "Times New Roman", serif; font-size: 17px; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  transition: color .25s ease, transform .35s cubic-bezier(.2, 1, .8, 1);
}
.srf-row:hover .srf-title { color: var(--accent); transform: translateX(3px); }
/* Same idea as the catalogue rows: the detail line holds its space so hovering
   never resizes the row, and fades in under the title. */
.srf-sub {
  font-size: 12px; height: 16px; line-height: 16px; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
  opacity: 0; transform: translateY(3px);
  transition: opacity .3s ease .05s, transform .3s var(--mtg-ease) .05s;
}
.srf-row:hover .srf-sub, .srf-row--adding .srf-sub { opacity: 1; transform: none; }

.srf-images { grid-area: images; display: flex; gap: 5px; align-items: center; }
.srf-img {
  display: block; width: 30px; height: 30px; border-radius: 4px; flex: 0 0 auto;
  background-size: cover; background-position: 50%; border: 1px solid var(--line);
  opacity: 0; transform: translateX(14%) scale(.8);
  transition: opacity .35s var(--mtg-ease), transform .35s var(--mtg-ease);
  transition-delay: calc((var(--n) - 1 - var(--i)) * 28ms);
}
.srf-row:hover .srf-img, .srf-row--adding .srf-img { opacity: 1; transform: none; }
/* Inspect one without opening the catalogue. The row-hover selector above is
   more specific than a bare .srf-img:hover, and hovering a tile necessarily
   hovers the row too, so the zoom has to be qualified the same way or it is
   silently overridden. */
.srf-row:hover .srf-img:hover,
.srf-row--adding .srf-img:hover {
  transform: scale(2.5); border-color: var(--accent); position: relative; z-index: 5;
  box-shadow: 0 8px 20px rgba(61, 52, 40, .28); transition-delay: 0s;
}
.srf-row:hover .srf-images .srf-img:last-child:hover,
.srf-row--adding .srf-images .srf-img:last-child:hover { transform-origin: right center; }

.srf-actions { grid-area: actions; }
.srf-addbtn { opacity: 0; transition: opacity .25s ease; white-space: nowrap; }
.srf-row:hover .srf-addbtn, .srf-addbtn:focus-visible, .srf-row--adding .srf-addbtn { opacity: 1; }
.srf-row--adding .srf-addbtn { visibility: hidden; }

.srf-chips {
  grid-area: chips; display: flex; flex-wrap: wrap; gap: 2px; align-items: center;
  max-height: 0; overflow: hidden; opacity: 0;
  transition: max-height .3s ease, opacity .3s ease, margin .3s ease;
}
.srf-row:hover .srf-chips, .srf-row--adding .srf-chips {
  max-height: 120px; opacity: 1; margin-top: 8px;
}
.srf-chips:empty { display: none; }

.srf-add {
  grid-area: add; display: none; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: 10px;
}
.srf-row--adding .srf-add { display: flex; }
.srf-add select { width: auto; min-width: 170px; }
.srf-add input[type=text] { width: 190px; }

@media (max-width: 820px) {
  .srf-row { grid-template-columns: 1fr auto; grid-template-areas: "main actions" "images images" "chips chips" "add add"; }
  .srf-images { margin-top: 8px; flex-wrap: wrap; }
}
@media (prefers-reduced-motion: reduce) {
  .srf-title, .srf-sub, .srf-img, .srf-addbtn, .srf-chips { transition: none !important; }
}

/* ---- Regions: same row language as surfaces ---- */
.rgn-row { grid-template-areas: "main flags actions" "add add add"; }
.rgn-flags { grid-area: flags; display: flex; align-items: center; gap: 8px; }
.rgn-code {
  font-variant-numeric: tabular-nums; font-size: 13.5px; color: var(--ink-soft);
  background: var(--panel-2); border: 1px solid var(--line); border-radius: 6px; padding: 2px 10px;
}
.rgn-actions { display: flex; gap: 8px; align-items: center; }
.rgn-actions form { margin: 0; }
/* The controls stay visible here: a region list is short, and hiding a
   destructive-ish toggle behind hover would be worse than a little ink. */
.rgn-row .srf-addbtn, .rgn-row .rgn-editbtn, .rgn-row .rgn-actions button { opacity: 1; }
.rgn-edit input[name=name] { width: 200px; }
.rgn-edit select { width: auto; }
@media (max-width: 820px) {
  .rgn-row { grid-template-areas: "main actions" "flags flags" "add add"; }
}

/* ---- Drag-and-drop upload fields ---- */
.dz {
  position: relative; display: block; margin-top: 4px;
  border: 2px dashed var(--line); border-radius: 10px; background: #fffdf6;
  padding: 16px 14px; text-align: center; cursor: pointer;
  transition: border-color .2s ease, background-color .2s ease;
}
.dz:hover { border-color: var(--accent); }
/* The real input covers the zone at zero opacity: clicks and native file
   drops both land on it, so drag-and-drop needs no DataTransfer juggling
   and the form still posts as an ordinary multipart submit. */
.dz input[type=file] {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; cursor: pointer;
}
.dz.is-over { border-color: var(--accent); background: var(--panel-2); }
.dz.has-file { border-style: solid; border-color: var(--ok); background: var(--ok-bg); }
.dz-text { font-size: 13.5px; color: var(--ink-soft); pointer-events: none; display: block; }
.dz-file { font-size: 13.5px; color: var(--ok); font-weight: 600; pointer-events: none; display: block; word-break: break-all; }
.dz:focus-within { border-color: var(--accent); box-shadow: 0 0 0 2px var(--panel-2); }
@media (prefers-reduced-motion: reduce) { .dz { transition: none; } }

.dz--rejected { animation: dz-reject 3s ease both; }
@keyframes dz-reject {
  0%, 55% { border-color: var(--err); background: var(--err-bg); border-style: solid; }
  100% { border-color: var(--line); background: #fffdf6; border-style: dashed; }
}
@media (prefers-reduced-motion: reduce) { .dz--rejected { animation: none; border-color: var(--err); } }

/* ---- Sub-tabs (Material catalogues | Materials) ---- */
.subtabs { display: flex; gap: 4px; margin-bottom: 20px; border-bottom: 1px solid var(--line); }
.subtabs a {
  text-decoration: none; color: var(--ink-soft); font-size: 14.5px; font-weight: 600;
  padding: 8px 18px 10px; border-radius: 8px 8px 0 0; position: relative; top: 1px;
  border: 1px solid transparent; border-bottom: none;
}
.subtabs a:hover { color: var(--accent); }
.subtabs a.active {
  color: var(--ink); background: var(--panel); border-color: var(--line);
}

/* ---- Materials library grid ---- */
.mat-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
  gap: 18px; align-items: start;
}
.mat-card { position: relative; }
.mat-face {
  display: block; width: 100%; padding: 0; border: none; background: none; cursor: pointer;
  border-radius: 10px;
}
.mat-img {
  display: block; width: 100%; aspect-ratio: 1; border-radius: 10px;
  background-size: cover; background-position: 50%; border: 1px solid var(--line);
  transition: transform .35s var(--mtg-ease-expo), box-shadow .35s var(--mtg-ease-expo), border-color .2s ease;
}
.mat-img--empty {
  display: flex; align-items: center; justify-content: center;
  color: var(--ink-soft); font-size: 13px; background: var(--panel-2);
}
.mat-card:hover .mat-img, .mat-face:focus-visible .mat-img {
  transform: scale(1.12); border-color: var(--accent);
  box-shadow: 0 10px 26px rgba(61, 52, 40, .22); z-index: 4; position: relative;
}
.mat-card:hover { z-index: 5; }
/* Name and tag: space reserved, revealed on hover so the grid stays calm. */
.mat-info {
  display: flex; flex-direction: column; gap: 2px; padding: 10px 4px 0; min-height: 64px;
  opacity: 0; transform: translateY(4px);
  transition: opacity .3s ease .05s, transform .3s var(--mtg-ease) .05s;
}
.mat-card:hover .mat-info, .mat-card--editing .mat-info, .mat-face:focus-visible ~ .mat-info { opacity: 1; transform: none; }
.mat-name { font-family: Georgia, serif; font-size: 15.5px; color: var(--ink); line-height: 1.2; }
.mat-tag {
  display: inline-block; font-size: 11px; text-transform: uppercase; letter-spacing: .06em; font-weight: 600;
  color: var(--accent); background: var(--panel-2); border: 1px solid var(--line);
  border-radius: 12px; padding: 1px 9px;
}
.mat-tag--none { color: var(--ink-soft); font-style: italic; text-transform: none; letter-spacing: 0; }
.mat-usage { font-size: 11.5px; }
@media (prefers-reduced-motion: reduce) { .mat-img, .mat-info { transition: none; } }

/* ---- Material editor modal: one bar, image left, options right, blurred page behind ---- */
.mat-modal {
  position: fixed; inset: 0; z-index: 60; display: flex; align-items: center; justify-content: center;
  padding: 24px; background: rgba(61, 52, 40, .35);
  -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px);
  opacity: 0; visibility: hidden; transition: opacity .3s ease, visibility 0s linear .3s;
}
.mat-modal.open { opacity: 1; visibility: visible; transition: opacity .3s ease; }
.mat-modal__bar {
  position: relative; display: flex; gap: 26px; align-items: stretch;
  width: min(860px, 100%); background: var(--panel); border: 1px solid var(--line);
  border-radius: 14px; padding: 22px; box-shadow: 0 24px 60px rgba(61, 52, 40, .35);
  transform: translateY(14px) scale(.97);
  transition: transform .35s var(--mtg-ease-expo);
}
.mat-modal.open .mat-modal__bar { transform: none; }
.mat-modal__img { flex: 0 0 min(340px, 42%); }
.mat-modal__img span {
  display: flex; align-items: center; justify-content: center; width: 100%; height: 100%;
  min-height: 300px; border-radius: 10px; border: 1px solid var(--line);
  background-color: var(--panel-2); background-size: cover; background-position: 50%;
  color: var(--ink-soft); font-size: 13px;
}
.mat-modal__form { flex: 1; display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.mat-modal__form label { margin-top: 8px; }
.mat-modal__actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 16px; }
.mat-modal__actions .danger[disabled] { opacity: .45; cursor: not-allowed; }
.mat-modal__close {
  position: absolute; top: 10px; right: 12px; border: none; background: none;
  color: var(--ink-soft); font-size: 15px; cursor: pointer; padding: 6px; line-height: 1;
}
.mat-modal__close:hover { color: var(--ink); }
@media (max-width: 720px) { .mat-modal__bar { flex-direction: column; } .mat-modal__img { flex-basis: auto; } .mat-modal__img span { min-height: 180px; } }
@media (prefers-reduced-motion: reduce) { .mat-modal, .mat-modal__bar { transition: none; } }

/* ---- Catalogue options: collapsible rows ---- */
details.opt {
  border: 1px solid var(--line); border-radius: 8px; margin-bottom: 10px;
  background: var(--panel-2); overflow: hidden;
}
details.opt > summary {
  list-style: none; cursor: pointer; user-select: none;
  display: flex; align-items: center; gap: 14px; padding: 10px 16px;
}
details.opt > summary::-webkit-details-marker { display: none; }
details.opt > summary:hover { background: var(--panel); }
.opt-chev { color: var(--accent); font-size: 13px; transition: transform .15s; flex: 0 0 auto; }
details.opt[open] .opt-chev { transform: rotate(90deg); }
.opt-main { flex: 1; min-width: 0; }
.opt-main .muted { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.opt-body { padding: 4px 16px 16px; border-top: 1px solid var(--line); background: var(--panel); }
@media (prefers-reduced-motion: reduce) { .opt-chev { transition: none; } }

/* ---- Add-material overlay: library grid + catalogue tray ---- */
#ddadd {
  position: fixed; inset: 0; z-index: 970; display: none; flex-direction: column;
  gap: 16px; padding: 30px clamp(20px, 4vw, 64px) 22px;
  background: var(--bg);
}
#ddadd.open { display: flex; }
.dd-close {
  position: absolute; top: 16px; right: 22px; background: none; border: none;
  font-size: 30px; line-height: 1; color: var(--ink-soft); cursor: pointer; padding: 8px;
}
.dd-close:hover { color: var(--accent); }
.dd-head { flex: 0 0 auto; }
.dd-title {
  margin: 0 0 4px; font-family: Georgia, "Times New Roman", serif; font-weight: normal;
  font-size: clamp(1.9rem, 4.6vw, 3.2rem); line-height: 1.05; color: var(--ink);
}
.dd-head .muted { max-width: 70ch; }
.dd-tags { display: flex; gap: 8px; flex-wrap: wrap; flex: 0 0 auto; }
.dd-tag {
  background: var(--panel); color: var(--ink); border: 1px solid var(--line);
  border-radius: 16px; padding: 5px 16px; font-size: 13.5px; cursor: pointer;
}
.dd-tag:hover { color: var(--accent); border-color: var(--accent); }
.dd-tag.active { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.dd-grid {
  flex: 1 1 auto; overflow-y: auto; padding: 6px 2px;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(148px, 1fr));
  gap: 16px; align-content: start;
}
/* Section headers inside the grid ("All" view): one per tag, full row,
   sticky so the current section stays named while scrolling. */
.dd-sect {
  grid-column: 1 / -1; position: sticky; top: -6px; z-index: 3;
  display: flex; align-items: baseline; gap: 10px;
  padding: 8px 2px 6px; margin-top: 6px;
  background: var(--bg); border-bottom: 1px solid var(--line);
}
.dd-sect:first-child { margin-top: 0; }
.dd-sect-name {
  font-family: Georgia, "Times New Roman", serif; font-size: 19px; color: var(--accent);
  text-transform: capitalize;
}
.dd-card { position: relative; border-radius: 10px; outline: none; }
.dd-card[draggable=true] { cursor: grab; }
.dd-card[draggable=true]:active { cursor: grabbing; }
.dd-card-img {
  aspect-ratio: 1; border-radius: 10px; border: 1px solid var(--line);
  background: var(--panel-2); background-size: cover; background-position: 50%;
  transition: transform .3s var(--mtg-ease-expo), box-shadow .3s var(--mtg-ease-expo), border-color .2s;
}
.dd-card[draggable=true]:hover .dd-card-img, .dd-card:focus-visible .dd-card-img {
  transform: scale(1.07); border-color: var(--accent);
  box-shadow: 0 10px 24px rgba(61, 52, 40, .2);
}
.dd-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.dd-card.dragging { opacity: .35; }
.dd-card-name { font-family: Georgia, serif; font-size: 14.5px; margin-top: 8px; line-height: 1.2; }
.dd-card-meta { font-size: 11.5px; }
.dd-card.dd-in .dd-card-img, .dd-card.dd-in .dd-card-name, .dd-card.dd-in .dd-card-meta { opacity: .38; }
.dd-badge { position: absolute; top: 8px; left: 8px; }
.dd-tray {
  flex: 0 0 auto; min-height: 84px;
  display: flex; align-items: center; gap: 16px; padding: 12px 18px;
  border: 2px dashed var(--line); border-radius: 12px; background: var(--panel);
  transition: border-color .2s, background-color .2s;
}
.dd-tray.is-over { border-color: var(--accent); background: var(--warn-bg); }
.dd-tray-label { flex: 0 0 auto; font-family: Georgia, serif; font-size: 16px; }
.dd-tray-thumbs { display: flex; gap: 6px; flex-wrap: wrap; flex: 1; }
.dd-tray-thumbs img {
  width: 40px; height: 40px; border-radius: 6px; border: 1px solid var(--line); object-fit: cover;
}
.dd-tray-thumbs img.dd-pop { animation: dd-pop .35s var(--mtg-ease-expo) both; border-color: var(--ok); }
@keyframes dd-pop { from { transform: scale(.3); opacity: 0; } to { transform: scale(1); opacity: 1; } }
.dd-tray-hint { flex: 0 0 auto; color: var(--ink-soft); font-size: 13px; font-style: italic; }
@media (prefers-reduced-motion: reduce) {
  .dd-card-img, .dd-tray { transition: none; }
  .dd-tray-thumbs img.dd-pop { animation: none; }
}

/* ---- Tags manager (declared vocabulary) ---- */
.tag-rows { display: flex; flex-direction: column; gap: 8px; margin: 12px 0 16px; }
.tag-row { display: flex; align-items: center; gap: 10px; }
.tag-row input[type=text] { max-width: 260px; }
.tag-row .nowrap { white-space: nowrap; font-size: 12.5px; min-width: 84px; }
.tag-row button[disabled] { opacity: .45; cursor: not-allowed; }
.tag-row--new { border-top: 1px dashed var(--line); padding-top: 14px; }
