/* Sample branding stylesheet — served by welcome itself at /theme.css.
   Point config/global.cssStylesheetUrl at this path (or replace this file
   with your own) to theme the portal without redeploying the app. */

@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap");

:root {
  --brand-blue-50: #eff6ff;
  --brand-blue-100: #dbeafe;
  --brand-blue-200: #bfdbfe;
  --brand-blue-500: #3b82f6;
  --brand-blue-600: #2563eb;
  --brand-blue-700: #1d4ed8;
  --brand-navy: #0f2a4a;
  --brand-gray-50: #f8fafc;
  --brand-gray-200: #e2e8f0;
  --brand-gray-500: #64748b;
  --brand-gray-700: #334155;
  --shadow-sm: 0 1px 2px rgba(15, 42, 74, 0.06);
  --shadow-md: 0 4px 14px rgba(15, 42, 74, 0.1);
  /* .portal-banner's rendered height (1rem padding + 40px icon buttons, top
     and bottom) — kept as a variable so .doc-frame (app/view/[repoId]) can
     size itself to exactly fill the rest of the viewport below it. */
  --nav-bar-height: 72px;
  /* Single source of truth for the brand photo, shared by .portal-banner
     (vivid) and body::before (faint grayscale wash) below — swap this one
     value to re-theme both at once, no new asset needed. --photo-bg-size /
     -position are shared too and matter just as much: both layers must use
     the *same* size/position formula (not each computing its own "cover"
     against its own differently-sized box) or the photo crop drifts out of
     alignment between the bar and the wash beneath it. */
  --photo-bg: url("/images/bar-background.jpg");
  --photo-bg-size: 100vw auto;
  --photo-bg-position: center top;
}

body {
  position: relative;
  font-family: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  background-color: #fbfcfe;
  color: var(--brand-gray-700);
  -webkit-font-smoothing: antialiased;
}

/* Faint grayscale wash of --photo-bg behind all page content — same photo,
   same crop as .portal-banner (see --photo-bg-size/-position above), just
   desaturated and low-opacity so text stays legible ("que permita la
   lectura"). A real fixed-position box rather than background-attachment:
   fixed on body itself, since body's own max-width keeps its padding box
   narrower than the viewport and throws that calculation off. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: var(--photo-bg) var(--photo-bg-position) / var(--photo-bg-size) no-repeat fixed;
  filter: grayscale(1);
  opacity: 0.05;
}

/* Lifts real content above the fixed wash layer (negative z-index) — needed
   because body's own stacking context would otherwise leave ordering
   ambiguous between the pseudo-element and body's normal-flow children. */
body > * {
  position: relative;
  z-index: 1;
}

.app-footer {
  position: fixed;
  bottom: 0;
  left: 0;
  width: 100%;
  text-align: center;
  padding: 0.6rem 0;
  font-size: 0.75rem;
  color: rgba(100, 116, 139, 0.7);
  pointer-events: none;
}

/* On the login screen's dark full-bleed background, the muted gray above
   would disappear — switch to a faint white there instead. */
body:has(.auth-shell) .app-footer {
  color: rgba(255, 255, 255, 0.55);
}

/* Build identification (app/layout.tsx, DOCKER_TAG baked in at image build
   time — see tools/build-images.sh / Dockerfile). Bottom-right corner,
   deliberately faint — an ops/debugging aid, not user-facing content. */
.build-tag {
  position: fixed;
  bottom: 0.4rem;
  right: 0.6rem;
  font-size: 1rem;
  color: rgba(255, 255, 255, 0.55);
  pointer-events: none;
}

body:has(.auth-shell) .build-tag {
  color: rgba(255, 255, 255, 0.3);
}

h1 {
  color: var(--brand-navy);
  font-weight: 700;
  font-size: 1.9rem;
  letter-spacing: -0.02em;
  margin-bottom: 0.25rem;
}

h1 + p {
  color: var(--brand-gray-500);
  margin-top: 0;
  margin-bottom: 1.75rem;
}

h2,
h3 {
  color: var(--brand-navy);
  font-weight: 600;
}

a {
  color: var(--brand-blue-600);
}

/* Repository cards on the home page */
.card-grid {
  gap: 1.25rem;
}

.card {
  background: #ffffff;
  border: 1px solid var(--brand-gray-200);
  border-radius: 14px;
  box-shadow: var(--shadow-sm);
  padding: 1.5rem;
  transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}

.card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
  border-color: var(--brand-blue-200);
}

.card h3 {
  color: var(--brand-blue-700);
  font-size: 1.05rem;
}

.card p {
  color: var(--brand-gray-500);
  font-size: 0.9rem;
  margin-bottom: 0;
}

/* Optional per-repo badge (docs_repos[].label in terraform.tfvars — e.g. a
   license tag) shown below the card's description. */
.card-label {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  white-space: nowrap;
  background: linear-gradient(135deg, #86efac, #4ade80);
  border: 1px solid rgba(21, 128, 61, 0.4);
  color: #000000;
  font-size: 0.62rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 0.25rem 0.65rem;
  border-radius: 999px;
  margin-top: 0.75rem;
  box-shadow: 0 1px 4px rgba(21, 128, 61, 0.25);
}

.card-label svg {
  width: 11px;
  height: 11px;
  flex-shrink: 0;
}

/* Login/register/set-password: full-bleed hero photo (apps/welcome/public/
   images/login-background.jpg) with a dark-to-transparent overlay (left to
   right) so the headline stays legible while the photo shows through on
   the right, behind the floating card. The negative margin +
   calc(-50vw + 50%) trick breaks .auth-shell out of body's max-width/
   padding (see globals.css) so it covers the whole viewport. */
.auth-shell {
  margin: -2rem calc(-50vw + 50%) -2rem;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 3rem;
  flex-wrap: wrap;
  box-sizing: border-box;
  padding: 3rem 6vw;
  font-family: "Plus Jakarta Sans", "Inter", system-ui, sans-serif;
  background-image: linear-gradient(
      100deg,
      rgba(8, 16, 35, 0.88) 0%,
      rgba(8, 16, 35, 0.68) 38%,
      rgba(8, 16, 35, 0.32) 62%,
      rgba(8, 16, 35, 0.08) 85%
    ),
    url("/images/login-background.jpg");
  background-size: cover;
  background-position: center top;
}

.auth-hero {
  flex: 1 1 380px;
  max-width: 560px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1.75rem;
}

.auth-hero-logo {
  height: 28px;
  width: auto;
  flex-shrink: 0;
}

.auth-hero-headline {
  margin: 0;
  font-family: "Plus Jakarta Sans", sans-serif;
  font-weight: 800;
  font-size: clamp(2.25rem, 5vw, 4rem);
  line-height: 1.05;
  letter-spacing: -0.02em;
  color: #ffffff;
  text-shadow: 0 6px 24px rgba(8, 20, 45, 0.45);
}

.auth-card {
  flex: 0 1 380px;
  width: 100%;
  max-width: 380px;
}

.auth-shell h1 {
  color: var(--brand-blue-100);
  font-size: 1.05rem;
  font-weight: 600;
  margin: 0 0 1rem;
  text-shadow: 0 2px 12px rgba(8, 20, 45, 0.35);
}

.auth-shell form.stacked {
  font-family: "Plus Jakarta Sans", "Inter", system-ui, sans-serif;
  background: rgba(255, 255, 255, 0.98);
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.5);
  box-shadow: 0 24px 60px -8px rgba(6, 16, 40, 0.5), 0 2px 10px rgba(6, 16, 40, 0.2);
}

@media (max-width: 860px) {
  .auth-shell {
    flex-direction: column;
    justify-content: center;
    text-align: center;
    padding: 2rem;
  }

  .auth-hero {
    align-items: center;
    text-align: center;
  }

  .auth-shell h1 {
    text-align: center;
  }
}

/* Forms (login + admin/users) */
form.stacked {
  box-sizing: border-box;
  background: #ffffff;
  border: 1px solid var(--brand-gray-200);
  border-radius: 14px;
  box-shadow: var(--shadow-sm);
  padding: 1.75rem;
  max-width: 380px;
  width: 100%;
}

label {
  display: block;
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--brand-gray-700);
  margin-bottom: 1rem;
}

input,
select {
  display: block;
  width: 100%;
  margin-top: 0.4rem;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--brand-gray-200);
  border-radius: 8px;
  font-size: 0.95rem;
  font-family: inherit;
  color: var(--brand-navy);
  background: var(--brand-gray-50);
  box-sizing: border-box;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

/* Password show/hide toggle (app/components/PasswordInput.tsx) */
.password-field {
  position: relative;
}

.password-field input {
  padding-right: 2.5rem;
}

.password-toggle {
  position: absolute;
  top: 50%;
  right: 0.4rem;
  transform: translateY(-50%);
  width: 28px;
  height: 28px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  box-shadow: none;
  color: var(--brand-gray-500);
}

.password-toggle:hover:not(:disabled) {
  color: var(--brand-gray-700);
  background: transparent;
  box-shadow: none;
  transform: translateY(-50%);
}

.password-toggle svg {
  width: 18px;
  height: 18px;
}

/* "Sign in with Google" button (app/components/GoogleSignInButton.tsx),
   matching Google's standard branding guidelines rather than the app's own
   blue button style. */
.google-signin-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  width: 100%;
  background: #ffffff;
  color: #3c4043;
  text-shadow: none;
  border: 1px solid #dadce0;
  border-radius: 4px;
  font-weight: 500;
  box-shadow: none;
}

.google-signin-button:hover:not(:disabled) {
  background: #f7f8f8;
  box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3);
  transform: none;
}

/* "Forgot password?" (app/login/page.tsx) — a <button> because it triggers
   client state/an email send, not navigation, but per specs/SPECS.md it
   should read as a link, not a second call-to-action button next to
   "Sign in". Strips the default button chrome down to plain link styling. */
.link-button {
  background: none;
  border: none;
  padding: 0;
  color: var(--brand-blue-600);
  font: inherit;
  font-weight: 500;
  text-shadow: none;
  box-shadow: none;
  cursor: pointer;
}

.link-button:hover:not(:disabled) {
  text-decoration: underline;
  background: none;
  box-shadow: none;
  transform: none;
}

.link-button:disabled {
  color: var(--brand-gray-500);
  cursor: default;
}

input:focus,
select:focus {
  outline: none;
  border-color: var(--brand-blue-500);
  box-shadow: 0 0 0 3px var(--brand-blue-100);
  background: #ffffff;
}

button {
  font-family: inherit;
  font-weight: 700;
  font-size: 0.95rem;
  color: #ffffff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
  background: linear-gradient(180deg, var(--brand-blue-500), var(--brand-blue-600));
  border: none;
  border-radius: 8px;
  padding: 0.6rem 1.1rem;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: transform 0.1s ease, box-shadow 0.1s ease, opacity 0.15s ease;
}

button:hover:not(:disabled) {
  box-shadow: var(--shadow-md);
  transform: translateY(-1px);
}

button:disabled {
  opacity: 0.6;
  cursor: default;
}

button[type="submit"]:not(:disabled) {
  background: linear-gradient(180deg, var(--brand-blue-600), var(--brand-blue-700));
}

/* Top banner on internal screens (home page), echoing the login screen's
   branding. Full-bleed like .auth-shell, but only at the top — content
   below stays within body's normal max-width. Uses the same --photo-bg
   size/position as body::before's faint wash (see :root) — the breakout
   margin below already makes this element's own box full viewport width,
   so `fixed` attachment resolves against the viewport here without the
   ambiguity body itself has, and the crop lines up seamlessly with the
   wash beneath it instead of each computing its own independent "cover".
   The ::before scrim guarantees the white logo/text stay legible over it
   ("set bright to produce a nice contrast" per specs/SPECS.md). */
.portal-banner {
  position: relative;
  margin: -2rem calc(-50vw + 50%) 0;
  overflow: hidden;
  box-shadow: 0 4px 20px rgba(8, 20, 45, 0.25);
  background: var(--photo-bg) var(--photo-bg-position) / var(--photo-bg-size) no-repeat fixed;
}

.portal-banner::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(120deg, rgba(10, 31, 68, 0.9) 0%, rgba(29, 78, 216, 0.55) 100%);
}

.portal-banner-inner {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem 2rem;
}

.portal-banner-brand {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  color: #ffffff;
  font-weight: 700;
  font-size: 1.5rem;
  letter-spacing: -0.02em;
  text-decoration: none;
  transition: opacity 0.15s ease;
}

.portal-banner-brand:hover {
  opacity: 0.85;
}

.portal-banner-logo {
  height: 28px;
  width: auto;
}

.portal-banner-actions {
  display: flex;
  align-items: center;
  gap: 1.25rem;
}

.portal-banner-link {
  color: #ffffff;
  font-weight: 500;
  font-size: 0.9rem;
  opacity: 0.9;
}

.portal-banner-link:hover {
  opacity: 1;
  text-decoration: underline;
}

.portal-banner form {
  margin: 0;
}

/* Home button and logout button (styled as a door), both circular icon
   buttons on the right of the banner — same box model, box-sizing set
   explicitly because .portal-banner-icon-button is an <a> (content-box by
   default) while .logout-door is a <button> (browsers default form
   controls to border-box) — without this they render at different sizes
   despite sharing every other rule, since the 1px border lands inside the
   box for one and outside it for the other. */
.portal-banner-icon-button,
.logout-door {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  width: 40px;
  height: 40px;
  flex-shrink: 0;
  padding: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.12);
  border: 1px solid rgba(255, 255, 255, 0.3);
  color: #ffffff;
  text-shadow: none;
  box-shadow: none;
}

.portal-banner-icon-button:hover {
  background: rgba(255, 255, 255, 0.22);
  box-shadow: none;
  transform: none;
}

/* Logout gets a solid red fill with a white outline/icon — a clear,
   deliberate visual signal distinct from the neutral glass-style home
   button, not just a tint.
   Selector specificity note: .logout-door is a <button type="submit">, so
   the generic button[type="submit"]:not(:disabled) rule above (0,2,1) was
   silently beating a plain .logout-door class (0,1,0) for `background` —
   border-color/color applied fine since that rule doesn't touch them, but
   background didn't. Matching its specificity exactly (element + class +
   attribute = 0,2,1) here, so it's a tie broken by source order in favor
   of this later rule, instead of guessing with !important. */
button.logout-door[type="submit"] {
  background: linear-gradient(180deg, #ef4444, #dc2626);
  border: 1.5px solid rgba(255, 255, 255, 0.85);
  color: #ffffff;
  box-shadow: 0 2px 8px rgba(220, 38, 38, 0.35);
}

button.logout-door[type="submit"]:hover:not(:disabled) {
  background: linear-gradient(180deg, #f87171, #ef4444);
  border-color: #ffffff;
  box-shadow: 0 4px 14px rgba(220, 38, 38, 0.45);
  transform: translateY(-1px);
}

.portal-banner-icon-button svg,
.logout-door svg {
  width: 20px;
  height: 20px;
}

.portal-shell {
  padding-top: 2.5rem;
}

/* Documentation micro-site viewer (app/view/[repoId]) — full-bleed like
   .auth-shell/.portal-banner (same calc(-50vw + 50%) trick to escape
   body's max-width), sized to exactly fill the viewport below the nav bar
   so there's no page-level scrollbar, only the iframe's own. An iframe is
   a replaced element (unlike <main>/<header>), so unlike those it needs an
   explicit width alongside the margin trick to actually reach 100vw. */
.doc-frame {
  display: block;
  width: 100vw;
  height: calc(100vh - var(--nav-bar-height));
  margin: 0 calc(-50vw + 50%) -2rem;
  border: none;
}

/* Downloads (app/downloads/[[...path]]) */
.download-breadcrumb {
  margin: 0.25rem 0 1.5rem;
  font-size: 0.9rem;
  color: var(--brand-gray-500);
}

.download-breadcrumb a {
  color: var(--brand-blue-600);
  text-decoration: none;
}

.download-breadcrumb a:hover {
  text-decoration: underline;
}

.download-breadcrumb-sep {
  color: var(--brand-gray-200);
  padding: 0 0.15rem;
}

/* Directory listing, styled like an ordinary file browser: a sortable
   Name/Description/Date/Size table rather than a card grid. */
.download-table {
  width: 100%;
}

.download-table th {
  padding: 0;
}

.download-sort-link {
  display: block;
  padding: 0.5rem;
  color: var(--brand-navy);
  text-decoration: none;
  white-space: nowrap;
}

.download-sort-link:hover {
  color: var(--brand-blue-600);
}

.download-sort-arrow {
  color: var(--brand-blue-600);
  font-size: 0.7em;
}

.download-th-right,
td.download-th-right {
  text-align: right;
}

.download-td-description {
  color: var(--brand-gray-500);
}

.download-table tbody tr:hover {
  background: var(--brand-blue-50);
}

.download-item-name {
  color: var(--brand-blue-700);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}

.download-item-name:hover {
  text-decoration: underline;
}

/* Conditions gate (the ?file= confirm view on the same page) */
.download-conditions {
  background: var(--brand-gray-50);
  border: 1px solid var(--brand-gray-200);
  border-radius: 12px;
  padding: 1.25rem 1.5rem;
  margin: 1rem 0 1.5rem;
  max-width: 640px;
}

.download-conditions :first-child {
  margin-top: 0;
}

.download-conditions :last-child {
  margin-bottom: 0;
}

.download-confirm-form {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1rem;
  max-width: 640px;
}

.download-conditions-accept {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  font-size: 0.9rem;
  color: var(--brand-gray-700);
}

.download-conditions-accept input[type="checkbox"] {
  margin-top: 0.2rem;
  width: auto;
}

.download-confirm-actions {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

/* "Back to files" (app/downloads/[[...path]]/page.tsx) — a secondary,
   lower-emphasis button next to the primary "Download" action. */
.button-secondary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: #ffffff;
  color: var(--brand-gray-700);
  text-shadow: none;
  border: 1px solid var(--brand-gray-200);
  border-radius: 8px;
  padding: 0.6rem 1.1rem;
  font-weight: 700;
  box-shadow: var(--shadow-sm);
}

.button-secondary:hover {
  background: var(--brand-gray-50);
  box-shadow: var(--shadow-md);
}

/* User table (admin/users) */
table {
  background: #ffffff;
  border: 1px solid var(--brand-gray-200);
  border-radius: 12px;
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  border-collapse: separate;
  border-spacing: 0;
}

th {
  background: var(--brand-blue-50);
  color: var(--brand-navy);
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border-bottom: 1px solid var(--brand-gray-200);
}

td {
  border-bottom: 1px solid var(--brand-gray-200);
  font-size: 0.9rem;
}

tr:last-child td {
  border-bottom: none;
}

[role="alert"] {
  color: #b91c1c;
  background: #fef2f2;
  border: 1px solid #fecaca;
  border-radius: 8px;
  padding: 0.6rem 0.8rem;
  font-size: 0.85rem;
  margin: 0;
}
