/* =========================================================================
   lml.css - shared styling for the LML project pages.

   Each page used to carry its own inline <style> block with its own fonts,
   colors and spacing, so nothing matched anything else. Those blocks are
   replaced by the tokens and components below.

   Light and dark are both selected, not an automatic inversion: the dark
   values are their own steps, checked against the dark surface. Every ink
   token clears 4.5:1 against its own page plane.
   ========================================================================= */

:root {
  color-scheme: light;

  /* surfaces - the warm yellow cream the original pages used (#fff6d6),
     stepped down slightly so white cards read as raised against it */
  --page: #fdf3d8;
  --surface: #fffaeb;
  --surface-raised: #ffffff;

  /* ink */
  --ink: #1c1917;
  --ink-secondary: #57504a;
  --ink-muted: #675e54;

  /* lines - tinted with the page so they read as edges, not gray rules */
  --line: #ecdfb6;
  --line-strong: #d8c694;

  /* accent - the warm brown the original pages were built around */
  --accent: #8a4b22;
  --accent-hover: #6d3a19;
  --accent-ink: #ffffff;
  --accent-wash: rgba(138, 75, 34, 0.08);

  /* data-viz accent, validated against the chart surface in both modes */
  --series-1: #1f6ac4;

  /* paper texture tint, used by the .paper--* backgrounds */
  --texture-rgb: 84 62 24;
  --texture-a: 0.07;

  --radius: 10px;
  --radius-sm: 6px;
  --shadow: 0 1px 2px rgba(84, 62, 24, 0.08), 0 4px 16px rgba(84, 62, 24, 0.09);
  --shadow-raised: 0 2px 4px rgba(84, 62, 24, 0.12), 0 12px 32px rgba(84, 62, 24, 0.16);

  --sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --measure: 68ch;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --page: #121211;
    --surface: #1a1a19;
    --surface-raised: #232321;
    --ink: #f0efec;
    --ink-secondary: #c3c2b7;
    --ink-muted: #999489;
    --line: #2c2c2a;
    --line-strong: #3a3a37;
    --accent: #e0a877;
    --accent-hover: #efbd90;
    --accent-ink: #1a1916;
    --accent-wash: rgba(224, 168, 119, 0.12);
    --series-1: #3987e5;
    --texture-rgb: 240 239 236;
    --texture-a: 0.05;
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 4px 16px rgba(0, 0, 0, 0.35);
    --shadow-raised: 0 2px 4px rgba(0, 0, 0, 0.5), 0 12px 32px rgba(0, 0, 0, 0.45);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --page: #121211;
  --surface: #1a1a19;
  --surface-raised: #232321;
  --ink: #f0efec;
  --ink-secondary: #c3c2b7;
  --ink-muted: #999489;
  --line: #2c2c2a;
  --line-strong: #3a3a37;
  --accent: #e0a877;
  --accent-hover: #efbd90;
  --accent-ink: #1a1916;
  --accent-wash: rgba(224, 168, 119, 0.12);
  --series-1: #3987e5;
  --texture-rgb: 240 239 236;
  --texture-a: 0.05;
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 4px 16px rgba(0, 0, 0, 0.35);
  --shadow-raised: 0 2px 4px rgba(0, 0, 0, 0.5), 0 12px 32px rgba(0, 0, 0, 0.45);
}

/* ------------------------------------------------------------------ base */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--page);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

/* -------------------------------------------------------------------------
   Paper textures.

   The lab's subject was the surface of photographic paper, so each tool page
   gets its own surface rather than its own accent color. These are
   background-image layers only: page color, cards and ink are identical on
   every page, so nothing shifts position and no text pair loses contrast.

   --texture-rgb and --texture-a carry the tint. Each pattern scales that
   alpha, because the three cover very different fractions of the page
   (grain about 11%, weave about 31%, grid about 8%) and would otherwise
   read at wildly different weights. The ceiling is set by where two layers
   cross: no crossing may drop muted ink below 4.5:1.
   ------------------------------------------------------------------------- */

.paper {
  background-color: var(--page);
}

/* The pattern is page decoration, so it comes off where it would only add
   noise: on paper, and under a user's forced color scheme. */
@media print {
  .paper { background-image: none; }
}

@media (forced-colors: active) {
  .paper { background-image: none; }
}

/* Image Processing: a fine matte grain. 6 and 11 are coprime, so the second
   dot field walks across the first for 66px before repeating and the
   stipple never settles into a visible lattice. */
.paper--grain {
  background-image:
    radial-gradient(rgb(var(--texture-rgb) / var(--texture-a)) 1px, transparent 1.1px),
    radial-gradient(rgb(var(--texture-rgb) / calc(var(--texture-a) * 0.8)) 0.9px, transparent 1px);
  background-size: 6px 6px, 11px 11px;
  background-position: 0 0, 4px 3px;
}

/* Texture Matching Lite: a crossed weave, the linen finish that fills the
   matcher's reference images. */
.paper--weave {
  background-image:
    repeating-linear-gradient(45deg,
      rgb(var(--texture-rgb) / calc(var(--texture-a) * 0.45)) 0 1px, transparent 1px 7px),
    repeating-linear-gradient(-45deg,
      rgb(var(--texture-rgb) / calc(var(--texture-a) * 0.45)) 0 1px, transparent 1px 7px);
}

/* Separators on a textured page.

   A hairline in --line sits within 1.07:1 of the pattern behind it, close
   enough that a rule stops reading as a separator and starts reading as a
   gridline that has drifted out of alignment. The rules with nothing but
   page on either side step up to --line-strong, roughly five times the
   separation. Borders that enclose an opaque box - cards, panels, notices -
   already read against their own fill and are left alone. */
.paper hr,
.paper .topbar,
.paper .hero,
.paper .site-footer {
  border-color: var(--line-strong);
}

/* A rule inside a panel sits on an opaque surface the pattern never
   reaches, so it keeps the lighter hairline. */
.paper .panel hr {
  border-color: var(--line);
}

/* Glyph-O-Matic: graph paper, the same grid the signature is plotted on. */
.paper--grid {
  background-image:
    repeating-linear-gradient(0deg,
      rgb(var(--texture-rgb) / var(--texture-a)) 0 1px, transparent 1px 24px),
    repeating-linear-gradient(90deg,
      rgb(var(--texture-rgb) / var(--texture-a)) 0 1px, transparent 1px 24px);
}

h1, h2, h3, h4 {
  line-height: 1.2;
  margin: 0 0 0.5em;
  font-weight: 650;
  letter-spacing: -0.015em;
}

h1 { font-size: clamp(1.9rem, 1.3rem + 2.4vw, 2.9rem); }
h2 { font-size: clamp(1.35rem, 1.1rem + 1vw, 1.75rem); }
h3 { font-size: 1.15rem; }

p { margin: 0 0 1rem; }

a {
  color: var(--accent);
  text-decoration: none;
  text-underline-offset: 0.2em;
}

a:hover,
a:focus-visible {
  color: var(--accent-hover);
  text-decoration: underline;
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}

img {
  max-width: 100%;
  height: auto;
}

code, kbd, samp {
  font-family: var(--mono);
  font-size: 0.9em;
}

hr {
  border: 0;
  border-top: 1px solid var(--line);
  margin: 2rem 0;
}

/* --------------------------------------------------------------- layout */

.wrap {
  width: 100%;
  max-width: 1120px;
  margin-inline: auto;
  padding-inline: clamp(1rem, 4vw, 2rem);
}

.wrap--narrow {
  max-width: 760px;
}

.main {
  flex: 1 0 auto;
  padding-block: clamp(2rem, 5vw, 3.5rem);
}

.prose {
  max-width: var(--measure);
}

.stack > * + * {
  margin-top: 1rem;
}

/* ------------------------------------------------------------------ nav */

.topbar {
  position: sticky;
  top: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--page) 88%, transparent);
  backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--line);
}

.topbar__inner {
  display: flex;
  align-items: center;
  gap: 1rem;
  min-height: 56px;
  flex-wrap: wrap;
}

.topbar__brand {
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.02em;
  margin-right: auto;
}

.topbar__brand:hover {
  color: var(--ink);
  text-decoration: none;
}

.topbar__links {
  display: flex;
  gap: 0.25rem;
  flex-wrap: wrap;
  list-style: none;
  margin: 0;
  padding: 0;
}

.topbar__links a {
  display: block;
  padding: 0.4rem 0.7rem;
  border-radius: var(--radius-sm);
  color: var(--ink-secondary);
  font-size: 0.93rem;
  font-weight: 500;
}

.topbar__links a:hover {
  background: var(--accent-wash);
  color: var(--accent);
  text-decoration: none;
}

.topbar__links a[aria-current="page"] {
  color: var(--ink);
  background: var(--accent-wash);
}

/* ----------------------------------------------------------------- hero */

.hero {
  padding-block: clamp(2.5rem, 7vw, 5rem);
  border-bottom: 1px solid var(--line);
}

.hero h1 {
  margin-bottom: 0.4em;
}

.hero__lead {
  font-size: clamp(1.02rem, 0.98rem + 0.35vw, 1.2rem);
  color: var(--ink-secondary);
  max-width: var(--measure);
  margin: 0;
}

/* ---------------------------------------------------------------- cards */

.grid {
  display: grid;
  gap: 1.25rem;
  grid-template-columns: repeat(auto-fit, minmax(265px, 1fr));
}

.card {
  display: flex;
  flex-direction: column;
  background: var(--surface-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.4rem;
  box-shadow: var(--shadow);
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}

a.card {
  color: inherit;
}

a.card:hover,
a.card:focus-visible {
  transform: translateY(-3px);
  box-shadow: var(--shadow-raised);
  border-color: var(--accent);
  text-decoration: none;
  color: inherit;
}

.card__title {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 0.4rem;
  font-size: 1.12rem;
  color: var(--ink);
}

a.card:hover .card__title {
  color: var(--accent);
}

.card__text {
  margin: 0;
  color: var(--ink-secondary);
  font-size: 0.94rem;
}

.card--muted {
  opacity: 0.72;
  box-shadow: none;
}

/* The arrow is decorative, so it is hidden from assistive tech. */
.card__arrow {
  margin-left: auto;
  color: var(--ink-muted);
  transition: transform 0.18s ease, color 0.18s ease;
}

a.card:hover .card__arrow {
  transform: translateX(3px);
  color: var(--accent);
}

/* ---------------------------------------------------------------- badge */

.badge {
  display: inline-block;
  font-size: 0.72rem;
  font-weight: 650;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 0.18rem 0.5rem;
  border-radius: 999px;
  border: 1px solid var(--line-strong);
  color: var(--ink-muted);
  background: var(--surface);
  vertical-align: middle;
  line-height: 1.5;
}

.badge--accent {
  border-color: transparent;
  background: var(--accent-wash);
  color: var(--accent);
}

/* --------------------------------------------------------------- notice */

/* A plain bordered block. The accent stripe that used to run down the left
   edge has been removed; the border is uniform on all four sides. */
.notice {
  border: 1px solid var(--line);
  background: var(--surface);
  border-radius: var(--radius-sm);
  padding: 1rem 1.15rem;
  color: var(--ink-secondary);
  font-size: 0.95rem;
}

/* A notice that has to be read before the rest of the page: tinted with the
   accent so it separates from the plain surfaces around it, and given more
   room than a standard notice. Every ink and link pairing on this tint
   clears 4.5:1 in both themes. */
.notice--highlight {
  background: var(--accent-wash);
  border-color: var(--accent);
  border-radius: var(--radius);
  padding: clamp(1.25rem, 1rem + 1vw, 1.9rem);
  margin-block: 0.5rem 2.75rem;
  font-size: 1rem;
  line-height: 1.7;
}

.notice--highlight > * + * {
  margin-top: 0.9rem;
}

.notice strong {
  color: var(--ink);
}

.notice > :last-child {
  margin-bottom: 0;
}

/* --------------------------------------------------------------- panels */

.panel {
  background: var(--surface-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.35rem;
  box-shadow: var(--shadow);
}

.panel__title {
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin: 0 0 0.9rem;
}

/* -------------------------------------------------------------- buttons */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  font: inherit;
  font-size: 0.93rem;
  font-weight: 550;
  padding: 0.5rem 0.9rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line-strong);
  background: var(--surface-raised);
  color: var(--ink);
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.btn:hover:not(:disabled) {
  background: var(--accent-wash);
  border-color: var(--accent);
  color: var(--accent);
  text-decoration: none;
}

.btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.btn--primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}

.btn--primary:hover:not(:disabled) {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
  color: var(--accent-ink);
}

.btn--block {
  width: 100%;
}

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

/* --------------------------------------------------------------- inputs */

label {
  display: block;
  font-size: 0.88rem;
  font-weight: 550;
  color: var(--ink-secondary);
  margin-bottom: 0.3rem;
}

input[type="text"],
input[type="email"],
input[type="number"],
input[type="file"],
select,
textarea {
  font: inherit;
  font-size: 0.93rem;
  width: 100%;
  padding: 0.45rem 0.6rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
}

input[type="range"] {
  width: 100%;
  accent-color: var(--accent);
}

.field + .field {
  margin-top: 1rem;
}

.hint {
  font-size: 0.85rem;
  color: var(--ink-muted);
  margin: 0.4rem 0 0;
}

/* -------------------------------------------------------------- status */

.status {
  min-height: 1.4rem;
  font-size: 0.9rem;
  margin: 0.7rem 0 0;
  color: var(--ink-secondary);
  /* Status lines quote the user's own filenames, which are often one long
     unbroken token. Without this the name runs straight out of the panel.
     "anywhere" rather than "break-word" so the min-content width collapses
     too, letting the grid track hold its size. */
  overflow-wrap: break-word;
  overflow-wrap: anywhere;
}

.status--error {
  color: #b3261e;
  font-weight: 600;
}

.status--ok {
  color: #006300;
  font-weight: 600;
}

:root[data-theme="dark"] .status--error,
:root:not([data-theme="light"]) .status--error {
  color: #ff9d94;
}

:root[data-theme="dark"] .status--ok,
:root:not([data-theme="light"]) .status--ok {
  color: #0ca30c;
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .status--error { color: #b3261e; }
  :root:not([data-theme="dark"]) .status--ok { color: #006300; }
}

/* -------------------------------------------------------- theme toggle */

.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line-strong);
  background: var(--surface-raised);
  color: var(--ink-secondary);
  cursor: pointer;
  flex: none;
}

.theme-toggle:hover {
  background: var(--accent-wash);
  color: var(--accent);
  border-color: var(--accent);
}

.theme-toggle svg {
  width: 17px;
  height: 17px;
}

/* Only one of the two icons shows, depending on the resolved theme. */
.theme-toggle .icon-moon { display: none; }
.theme-toggle .icon-sun { display: block; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .icon-sun { display: none; }
  :root:not([data-theme="light"]) .theme-toggle .icon-moon { display: block; }
}

:root[data-theme="dark"] .theme-toggle .icon-sun { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display: block; }
:root[data-theme="light"] .theme-toggle .icon-sun { display: block; }
:root[data-theme="light"] .theme-toggle .icon-moon { display: none; }

/* --------------------------------------------------------------- footer */

.site-footer {
  border-top: 1px solid var(--line);
  padding-block: 1.75rem;
  color: var(--ink-muted);
  font-size: 0.9rem;
}

.site-footer p {
  margin: 0;
}

/* The footer carries the lab name, so this line keeps the site from
   reading as something Yale publishes. */
.site-footer__note {
  margin-top: 0.4rem !important;
  font-size: 0.85rem;
  color: var(--ink-muted);
}

/* ------------------------------------------------------------- utility */

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.text-muted { color: var(--ink-muted); }
.mt-0 { margin-top: 0; }
.mb-0 { margin-bottom: 0; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}
