File size: 3,895 Bytes
de1e3fc
 
 
 
b5442b0
 
 
 
 
 
 
 
de1e3fc
 
 
 
 
 
7f48c4d
 
de1e3fc
 
 
 
 
 
9122959
7f48c4d
 
 
de1e3fc
 
 
 
 
 
 
 
 
 
 
9122959
de1e3fc
 
 
 
 
9122959
de1e3fc
 
 
 
9fd72d6
 
 
 
 
 
de1e3fc
b5442b0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
@tailwind base;
@tailwind components;
@tailwind utilities;

/* Self-hosted fonts (no external CDN). Inter = body/UI, Fraunces = display headings. */
@font-face { font-family: "Inter"; font-weight: 400; font-display: swap; src: url("/fonts/inter-400.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-weight: 500; font-display: swap; src: url("/fonts/inter-500.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-weight: 600; font-display: swap; src: url("/fonts/inter-600.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-weight: 700; font-display: swap; src: url("/fonts/inter-700.woff2") format("woff2"); }
@font-face { font-family: "Fraunces"; font-weight: 600; font-display: swap; src: url("/fonts/fraunces-600.woff2") format("woff2"); }
@font-face { font-family: "Fraunces"; font-weight: 700; font-display: swap; src: url("/fonts/fraunces-700.woff2") format("woff2"); }

@layer base {
  /* Warm cream page with a faint paper grain so the background doesn't read as flat/sterile.
     The grain is a self-contained inline SVG fractal-noise (no external asset), fixed to the
     viewport so it stays put while content scrolls. Cards sit opaque on top of it. */
  body {
    @apply bg-gray-50 text-gray-900;
    /* Paper grain — bumped to be clearly visible (coarser + higher opacity than before). */
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='p'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.7' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23p)' opacity='0.12'/%3E%3C/svg%3E");
    background-attachment: fixed;
  }
}

@layer components {
  .btn {
    @apply inline-flex items-center justify-center rounded-md px-4 py-2 text-sm font-medium transition disabled:opacity-50 disabled:cursor-not-allowed;
    /* Finer grain than the page background (higher frequency, lower opacity) so buttons pick up the
       same paper feel without looking rough. Layers over each variant's background color below. */
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='b'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23b)' opacity='0.09'/%3E%3C/svg%3E");
  }
  .btn-primary {
    @apply btn bg-brand-600 text-white hover:bg-brand-700;
  }
  .btn-secondary {
    @apply btn bg-white text-gray-800 border border-gray-300 hover:bg-gray-50;
  }
  .btn-danger {
    @apply btn bg-red-600 text-white hover:bg-red-700;
  }
  .input {
    @apply w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:border-brand-500 focus:ring-1 focus:ring-brand-500 outline-none;
  }
  .label {
    @apply block text-sm font-medium text-gray-700 mb-1;
  }
  .card {
    @apply rounded-lg border border-gray-200 bg-white p-4 shadow-sm;
  }
  .badge {
    @apply inline-block rounded-full px-2 py-0.5 text-xs font-medium;
  }
  /* Inline citation links (Credits). Tailwind's preflight resets anchors to
     `color: inherit; text-decoration: inherit`, so without this every <a> renders as plain body
     text and reads as if the link were never added. */
  .link {
    @apply text-leaf-700 underline underline-offset-2 hover:text-leaf-800;
  }
}

/* Scanning line that sweeps down a photo while it's being embedded/searched. */
@keyframes scan-sweep {
  0% { top: 4%; opacity: 0; }
  15% { opacity: 1; }
  85% { opacity: 1; }
  100% { top: 96%; opacity: 0; }
}
.scan-sweep {
  animation: scan-sweep 1.15s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
  .scan-sweep {
    animation: none;
    top: 50%;
  }
}