/* Eidoko portal styles, following docs/brand.md (light only: Rob dropped dark mode for the portal). Everything visual hangs off the tokens on :root below.
   Every page, client project pages included, uses the same system: clients are named in text only. */

/* ── Fonts: self-hosted, OFL (static/fonts/LICENSES.md) ── */
@font-face { font-family: "Hanken Grotesk"; src: url("fonts/hanken-grotesk-latin-wght.woff2") format("woff2"); font-weight: 400 600; font-display: swap; }
@font-face { font-family: "IBM Plex Mono"; src: url("fonts/ibm-plex-mono-latin-400.woff2") format("woff2"); font-weight: 400; font-display: swap; }
@font-face { font-family: "IBM Plex Mono"; src: url("fonts/ibm-plex-mono-latin-500.woff2") format("woff2"); font-weight: 500; font-display: swap; }

:root {
  /* Typeface: --font-brand = headings, --font-text = everything else (the wordmark is Archivo, outlined in its SVGs) */
  --font-brand: "Hanken Grotesk", var(--sans); --font-text: "Hanken Grotesk", var(--sans);
  --font-mono: "IBM Plex Mono", ui-monospace, Consolas, monospace;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  /* Palette */
  --red: #D2553F; --cyan: #1FA6B8; --ink: #1B2A22; --paper: #F5F3EF; --red-tint: #FBE5E0; --cyan-tint: #E0F2F5;
  --red-text: #B8442F; --cyan-text: #137A88; /* red and cyan as small text */

  /* Roles */
  --bg: var(--paper); --surface: #FFFFFF; --fg: var(--ink); --muted: #5D6761; --line: #DAD6CE;
  --btn-bg: var(--ink); --btn-fg: var(--paper);

  /* Devices */
  --shadow: 4px 4px 0 var(--cyan), -2px -2px 0 var(--red);           /* primary button and card (04a) */
  --shadow-hover: 6px 6px 0 var(--cyan), -2px -2px 0 var(--red);
  --shadow-pressed: 2px 2px 0 var(--cyan), -1px -1px 0 var(--red);
  --shadow-secondary: 3px 3px 0 var(--cyan);
  /* the double rule: red 1.5px line, cyan line 4px lower and 4px right, both container width - 4px */
  --double-rule: linear-gradient(var(--red), var(--red)) 0 0 / calc(100% - 4px) 1.5px no-repeat,
                 linear-gradient(var(--cyan), var(--cyan)) 4px 4px / calc(100% - 4px) 1.5px no-repeat;

  color-scheme: light; /* no dark mode: the portal is always paper and ink, whatever the device setting */
}

/* ── Base ── */
* { box-sizing: border-box; }
body { margin: 0; background: var(--bg); color: var(--fg); font-family: var(--font-text); font-weight: 400; font-size: 16px;
  line-height: 1.6; -webkit-font-smoothing: antialiased; }
a { color: var(--fg); text-decoration-color: var(--cyan); text-decoration-thickness: 1.5px; text-underline-offset: 3px; }
a:hover { color: var(--cyan-text); }
:focus-visible { outline: 2px solid var(--cyan); outline-offset: 3px; }
strong, b { font-weight: 600; }
em { font-style: normal; color: var(--muted); } /* no italics in the UI */
code { font-family: var(--font-mono); font-size: .875em; }
h1, h2, h3 { font-family: var(--font-brand); color: var(--fg); font-weight: 500; }
h1 { font-size: 34px; line-height: 1.1; letter-spacing: -.01em; margin: 0 0 12px; }
h2 { font-size: 24px; line-height: 1.2; margin: 0 0 12px; }
h3 { font-size: 18px; line-height: 1.3; margin: 0 0 4px; }
.accent { color: var(--cyan-text); }
.lead { max-width: 68ch; }
.muted { color: var(--muted); }
.small-text, .muted.small, .comments-soon { font-size: 14px; line-height: 1.5; }
main { max-width: 1180px; margin: 0 auto; padding: 32px 16px 64px; counter-reset: plate; }

/* Mono: labels (kickers, table heads, field names, crumbs, badges) */
.label, .crumbs, .badge, .status, th, .toc, .top nav, form label:not(.check) {
  font-family: var(--font-mono); font-size: 11px; line-height: 1.4; letter-spacing: .14em; text-transform: uppercase; font-weight: 500; }
.label { color: var(--red-text); margin: 0 0 8px; }
.crumbs { margin: 0 0 24px; color: var(--muted); }
.crumbs a { color: inherit; }

/* The double rule between sections */
hr.rule { border: 0; height: 5.5px; margin: 24px 0 32px; background: var(--double-rule); }

/* ── Header and the wordmark (outlined master SVGs; 28px type size = 21px tall, 86.5px wide) ── */
.top { display: flex; justify-content: space-between; align-items: center; gap: 8px 20px; padding: 14px 20px;
  border-bottom: 1px solid var(--line); background: var(--bg); flex-wrap: wrap; }
.brand { display: inline-flex; padding: 0; line-height: 0; }
.wordmark { display: block; height: 21px; width: auto; }
.top nav { display: flex; align-items: center; gap: 6px 20px; flex-wrap: wrap; }
.top nav form { margin: 0; }
.top nav a, .top nav button.link { color: var(--fg); text-decoration: none; letter-spacing: inherit; font: inherit; text-transform: inherit; }
.top nav a:hover, .top nav button.link:hover { color: var(--cyan-text); }
.who { color: var(--muted); overflow-wrap: anywhere; text-transform: none; letter-spacing: .02em; }

/* ── Cards (04a): white, square, no border, the offset shadow; dense lists are hairline rows, not cards ── */
.card { background: var(--surface); box-shadow: var(--shadow); padding: 16px 18px; margin: 24px 0; }
.block { margin: 40px 0; }
.narrow { max-width: 480px; margin: 56px auto; }
.danger-zone { box-shadow: 4px 4px 0 var(--red); }

/* ── Buttons ── */
.button, button { display: inline-block; background: var(--btn-bg); color: var(--btn-fg); border: 0; border-radius: 0;
  padding: 10px 18px; margin: 2px 6px 6px 2px; font: inherit; font-size: 15px; font-weight: 500; line-height: 1.3; cursor: pointer;
  text-decoration: none; box-shadow: var(--shadow); transition: box-shadow .12s, transform .12s; }
.button:hover, button:hover { color: var(--btn-fg); box-shadow: var(--shadow-hover); }
.button:active, button:active { transform: translate(2px, 2px); box-shadow: var(--shadow-pressed); }
.button.secondary, button.secondary { background: transparent; color: var(--fg); border: 1.5px solid var(--fg); box-shadow: var(--shadow-secondary); }
.button.secondary:active, button.secondary:active { box-shadow: none; }
button.small { padding: 5px 11px; font-size: 14px; }
button.danger { background: transparent; color: var(--red-text); border: 1.5px solid currentColor; box-shadow: none; }
button.danger:hover { background: var(--red-tint); }
button.link { background: none; color: var(--fg); padding: 0; margin: 0; font-weight: 400; box-shadow: none; text-decoration: underline;
  text-decoration-color: var(--cyan); }
button.link:active { transform: none; }

/* ── Forms ── */
label { display: flex; flex-direction: column; gap: 6px; color: var(--muted); }
label code { text-transform: none; color: var(--fg); font-size: 1.1em; letter-spacing: .02em; }
label.check { flex-direction: row; align-items: center; gap: 8px; color: var(--fg); font-size: 15px; }
input, textarea, select { font: inherit; font-family: var(--font-text); font-size: 16px; letter-spacing: normal; text-transform: none;
  font-weight: 400; color: var(--fg); background: var(--surface); border: 1.5px solid var(--line); border-radius: 0;
  padding: 8px 10px; max-width: 100%; }
input:focus, textarea:focus, select:focus { border-color: var(--fg); outline: none; box-shadow: 3px 3px 0 var(--cyan); }
input[type="checkbox"] { accent-color: var(--ink); width: 17px; height: 17px; }
input[type="file"] { font-size: 14px; }
input[readonly], textarea[readonly] { background: var(--bg); font-family: var(--font-mono); font-size: 13px; }
form.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; align-items: end; }
form.grid .wide { grid-column: 1 / -1; }
form.inline { display: flex; gap: 14px; align-items: end; flex-wrap: wrap; margin-top: 14px; }
form.row { display: flex; gap: 8px; align-items: center; margin: 0; }

/* ── Tables (hairline rows), badges, flashes ── */
table { width: 100%; border-collapse: collapse; font-size: 15px; display: block; overflow-x: auto; }
th, td { text-align: left; padding: 9px 10px; border-bottom: 1px solid var(--line); vertical-align: middle; }
th { color: var(--muted); border-bottom-color: var(--fg); white-space: nowrap; }
td form { margin: 0; }
.badge, .status { display: inline-block; padding: 3px 8px 2px; border: 1px solid var(--line); color: var(--fg);
  background: var(--surface); vertical-align: middle; letter-spacing: .1em; }
.badge.ok { background: var(--cyan-tint); border-color: transparent; }
.flash { padding: 12px 16px; border-left: 3px solid var(--cyan); background: var(--cyan-tint); }
.flash.err { border-left-color: var(--red); background: var(--red-tint); }

/* ── Home ── */
.projects { list-style: none; padding: 0; margin: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(290px, 1fr)); gap: 24px; }
.projects li { margin: 0; display: flex; flex-direction: column; }
.projects h3 { margin: 0 0 4px; }
.projects a { text-decoration: none; }
.projects a:hover { color: var(--cyan-text); }
.projects p:not(.label) { margin: 0; font-size: 14px; line-height: 1.5; color: var(--muted); }

/* ── Project page ── */
.page-head .status, .page-head .badge { margin: 0 6px 6px 0; }
.toc { display: flex; gap: 8px 22px; flex-wrap: wrap; margin: 20px 0 0; }
.section { margin: 0 0 48px; scroll-margin-top: 16px; }
.welcome { max-width: 640px; margin: 0 0 48px; }
.welcome h2 { margin-top: 0; }

/* Images: plain, square, no frame. Caption: "Pl. 03" in red, two spaces, the caption in muted */
figure { margin: 0; }
figcaption { font-family: var(--font-mono); font-size: 12px; line-height: 1.5; letter-spacing: .02em; color: var(--muted); padding: 8px 0 0; }
figcaption::before { counter-increment: plate; content: "Pl. " counter(plate, decimal-leading-zero); color: var(--red-text); margin-right: 2ch; }
.gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 24px 20px; }
.gallery img { width: 100%; aspect-ratio: 16 / 10; object-fit: cover; display: block; background: var(--line); }
.gallery .pictures { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 4px; }
/* a view's pictures together (the model render and its photoreal pass): the plate spans two gallery columns */
.gallery .pair { grid-column: span 2; }
@media (max-width: 600px) { .gallery .pair { grid-column: auto; } }  /* a pair stays side by side: model left, final right */
.sheets { display: grid; gap: 32px; }
.sheets img, .videos video { width: 100%; height: auto; display: block; background: var(--line); }
.videos { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(420px, 100%), 1fr)); gap: 24px 20px; }
.comments-soon { border-top: 1px dashed var(--line); padding-top: 8px; margin-top: 16px; }

/* ── Manage page ── */
.set { border-top: 1px solid var(--line); padding: 20px 0; }
.set:first-of-type { border-top: 0; padding-top: 0; }
.block .set:first-of-type { border-top: 1px solid var(--fg); padding-top: 20px; }
.set h3 .badge { margin-left: 4px; }
.set.invite-row, .set.invite-row:first-of-type { border-top: 1px solid var(--line); padding-top: 18px; margin-top: 20px; }
.invite-row label { margin-top: 8px; }
.invite-row input[readonly] { width: 100%; }
.invite-row form { margin-top: 12px; }
.invite { margin-top: 14px; }
.invite summary { cursor: pointer; text-decoration: underline; text-decoration-color: var(--cyan); text-decoration-thickness: 1.5px;
  text-underline-offset: 3px; }
.invite label { margin-top: 10px; }
.invite input, .invite textarea { width: 100%; }

/* ── Signed-out home: the wordmark (type size clamp(64px, 14vw, 160px), so 3.09x wide, 0.75x tall) centred about
   45% from the top, the Sign in button 48px below it, an error line in between when there is one ── */
.landing { --type: clamp(64px, 14vw, 160px); max-width: none; min-height: 100vh; min-height: 100svh; margin: 0;
  position: relative; isolation: isolate;
  padding: calc(45vh - var(--type) * .375) 16px 32px; padding-top: calc(45svh - var(--type) * .375);
  display: flex; flex-direction: column; align-items: center; }
/* the animated backdrop (static/home-backdrop.js): this page only, behind everything, no layout of its own */
.landing-backdrop { position: fixed; inset: 0; width: 100%; height: 100%; z-index: -1; pointer-events: none; }
.landing-mark { margin: 0; line-height: 0; }
.landing-mark img { display: block; width: calc(var(--type) * 3.09); max-width: 100%; height: auto; }
.landing-actions { margin: 48px 0 0; display: flex; gap: 16px; flex-wrap: wrap; justify-content: center; }
.landing-actions .button { margin: 0; }
/* the invitation page: the same landing, the invitation under the wordmark */
.landing-invite { max-width: 36rem; margin: 24px 0 0; padding: 16px 24px 24px; text-align: center;
  /* a soft paper glow, so the text reads cleanly over the backdrop lines */
  background: radial-gradient(closest-side, rgb(245 243 239 / .94) 72%, rgb(245 243 239 / 0)); }
.landing-invite h1 { font-size: 28px; line-height: 1.2; margin: 0 0 12px; }
.landing-invite .muted { margin: 0; }
.landing-invite .landing-actions { margin-top: 32px; }
.landing-error { margin: 24px 0 -24px; font-size: 14px; line-height: 1.5; color: var(--red-text); text-align: center; }

@media (max-width: 520px) {
  h1 { font-size: 28px; }
  main { padding-top: 24px; }
  .narrow { margin-top: 24px; }
}

/* The walkable model page: header and a slim bar, then the Godot build filling the rest of the window */
.model-page { height: 100vh; height: 100dvh; display: flex; flex-direction: column; overflow: hidden; }
.model-bar { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 16px; padding: 8px 20px;
  border-bottom: 1px solid var(--line); font: 500 12px/1.4 var(--font-mono); letter-spacing: .08em; text-transform: uppercase; }
.model-bar a { color: var(--fg); }
.model-bar a::before { content: "← "; }
.model-title { color: var(--red-text); }
.model-keys { margin-left: auto; color: var(--muted); text-transform: none; letter-spacing: 0; }
.model-stage { position: relative; flex: 1; min-height: 0; background: var(--ink); }
.model-stage iframe { display: block; width: 100%; height: 100%; border: 0; }
@media (max-width: 640px) { .model-keys { display: none; } }

/* The picture viewer (static/gallery.js): full screen on ink, mono bar on top, the fade slider below a pair */
.gallery a, .sheets a { cursor: zoom-in; }
html.viewer-open { overflow: hidden; }
dialog.viewer { width: 100vw; height: 100vh; height: 100dvh; max-width: none; max-height: none; margin: 0; padding: 0;
  border: 0; background: var(--ink); color: var(--paper); display: none; flex-direction: column; }
dialog.viewer[open] { display: flex; }
dialog.viewer::backdrop { background: var(--ink); }
.viewer-bar { display: flex; align-items: baseline; gap: 6px 16px; flex-wrap: wrap; padding: 12px 20px;
  font: 500 12px/1.4 var(--font-mono); letter-spacing: .06em; }
.viewer-plate { color: var(--red); }
.viewer-caption { color: var(--paper); }
.viewer-count { margin-left: auto; color: #A9B0AB; }
.viewer-bar a, .viewer-bar button.link { color: var(--paper); text-transform: uppercase; }
.viewer-bar button.link { background: none; border: 0; padding: 0; box-shadow: none; font: inherit; letter-spacing: inherit; cursor: pointer; }
.viewer-stage { position: relative; flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center; padding: 8px 64px 16px; }
/* the pictures fill the space left between the top bar and the fade bar, letterboxed, so nothing overlaps */
.viewer-frame { position: relative; width: 100%; height: 100%; transition: opacity .18s; }
.viewer-frame.swap { opacity: 0; }
.viewer-frame img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; display: block; }
.viewer-over.animate { transition: opacity .6s ease; }
.viewer-prev, .viewer-next { position: absolute; top: 50%; transform: translateY(-50%); background: transparent; color: var(--paper);
  border: 1px solid rgba(245, 243, 239, .35); box-shadow: none; width: 44px; height: 44px; padding: 0; font-size: 20px; line-height: 1; }
.viewer-prev { left: 12px; } .viewer-next { right: 12px; }
.viewer-prev:hover, .viewer-next:hover { border-color: var(--paper); box-shadow: none; }
.viewer-fade { display: grid; grid-template-columns: auto min(360px, 60vw) auto; justify-content: center; align-items: center;
  gap: 10px 12px; padding: 10px 20px 16px;
  font: 500 12px/1 var(--font-mono); letter-spacing: .06em; text-transform: uppercase; color: #A9B0AB; }
.viewer-fade[hidden] { display: none; }
/* the slider drawn the same in every browser: a thin paper track, red up to the thumb, a red 16 px thumb */
.viewer-fade input { -webkit-appearance: none; appearance: none; width: 100%; height: 16px; margin: 0; padding: 0; border: 0;
  background: transparent; cursor: pointer; }
.viewer-fade input::-webkit-slider-runnable-track { height: 4px; background: rgba(245, 243, 239, .3); }
.viewer-fade input::-moz-range-track { height: 4px; background: rgba(245, 243, 239, .3); }
.viewer-fade input::-moz-range-progress { height: 4px; background: var(--red); }
.viewer-fade input::-webkit-slider-thumb { -webkit-appearance: none; width: 16px; height: 16px; margin-top: -6px; border: 0;
  border-radius: 50%; background: var(--red); }
.viewer-fade input::-moz-range-thumb { width: 16px; height: 16px; border: 0; border-radius: 50%; background: var(--red); }
@media (max-width: 640px) { .viewer-stage { padding: 0 8px; } .viewer-prev, .viewer-next { display: none; } }
.viewer-stage:focus { outline: none; }
/* the fade slider: no field-style focus box (the thumb shows where it is) */
.viewer-fade input:focus, .viewer-fade input:focus-visible { outline: none; box-shadow: none; border-color: transparent; }
/* keycaps for 1 / 2 / 3: a key face with a darker lip, the current one in red */
/* each key under its point on the slider: 0 % (left end), 50 %, 100 % (right end); 8 px = half the slider's thumb */
.viewer-keys { grid-column: 2; position: relative; height: 30px; }
.viewer-keys .key { position: absolute; top: 0; transform: translateX(-50%); }
.viewer-keys .at-0 { left: 8px; } .viewer-keys .at-50 { left: 50%; } .viewer-keys .at-100 { left: calc(100% - 8px); }
.viewer-fade .key { width: 28px; height: 28px; margin: 0; padding: 0; display: inline-flex; align-items: center; justify-content: center;
  font: 500 13px/1 var(--font-mono); color: var(--paper); background: #2B3A32; border: 1px solid #5A6862; border-radius: 4px;
  box-shadow: 0 2px 0 #0E1712; transition: transform .08s, box-shadow .08s, color .12s; }
.viewer-fade .key:hover { border-color: var(--paper); box-shadow: 0 2px 0 #0E1712; }
.viewer-fade .key:active { transform: translate(-50%, 2px); box-shadow: none; }
.viewer-fade .key.on { color: var(--red); border-color: var(--red); }

/* Two-step confirmations (removing someone, requesting deletion): the summary looks like a small danger button and
   opens the real one with a question */
details.confirm { display: inline-block; }
details.confirm > summary { list-style: none; display: inline-block; cursor: pointer; padding: 5px 11px; font-size: 14px;
  font-weight: 500; color: var(--red-text); border: 1.5px solid currentColor; margin: 2px 6px 6px 2px; }
details.confirm > summary::-webkit-details-marker { display: none; }
details.confirm form { display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 0; }

/* The admin's "View as" switch in the top nav; red while previewing the site as a client */
.view-as { display: flex; align-items: center; gap: 8px; margin: 0; }
.view-as label { display: flex; flex-direction: row; align-items: center; gap: 8px; margin: 0; }
.view-as select { font: inherit; text-transform: none; letter-spacing: 0; padding: 3px 6px; border: 1.5px solid var(--line);
  background: var(--surface); color: var(--fg); }
.view-as.previewing select { border-color: var(--red); color: var(--red-text); }
.view-as.previewing span { color: var(--red-text); }
.view-as.auto .view-as-go { display: none; }

/* The client's own files at the end of every project page */
.file-drop { display: flex; flex-wrap: wrap; align-items: end; gap: 12px 16px; padding: 16px 18px; margin: 0 0 20px;
  border: 1.5px dashed var(--line); background: var(--surface); }
.file-drop label { flex: 1 1 320px; }
.file-list td:first-child a { word-break: break-all; }
