*, ::before, ::after {
  --tw-border-spacing-x: 0;
  --tw-border-spacing-y: 0;
  --tw-translate-x: 0;
  --tw-translate-y: 0;
  --tw-rotate: 0;
  --tw-skew-x: 0;
  --tw-skew-y: 0;
  --tw-scale-x: 1;
  --tw-scale-y: 1;
  --tw-pan-x:  ;
  --tw-pan-y:  ;
  --tw-pinch-zoom:  ;
  --tw-scroll-snap-strictness: proximity;
  --tw-gradient-from-position:  ;
  --tw-gradient-via-position:  ;
  --tw-gradient-to-position:  ;
  --tw-ordinal:  ;
  --tw-slashed-zero:  ;
  --tw-numeric-figure:  ;
  --tw-numeric-spacing:  ;
  --tw-numeric-fraction:  ;
  --tw-ring-inset:  ;
  --tw-ring-offset-width: 0px;
  --tw-ring-offset-color: #fff;
  --tw-ring-color: rgb(59 130 246 / 0.5);
  --tw-ring-offset-shadow: 0 0 #0000;
  --tw-ring-shadow: 0 0 #0000;
  --tw-shadow: 0 0 #0000;
  --tw-shadow-colored: 0 0 #0000;
  --tw-blur:  ;
  --tw-brightness:  ;
  --tw-contrast:  ;
  --tw-grayscale:  ;
  --tw-hue-rotate:  ;
  --tw-invert:  ;
  --tw-saturate:  ;
  --tw-sepia:  ;
  --tw-drop-shadow:  ;
  --tw-backdrop-blur:  ;
  --tw-backdrop-brightness:  ;
  --tw-backdrop-contrast:  ;
  --tw-backdrop-grayscale:  ;
  --tw-backdrop-hue-rotate:  ;
  --tw-backdrop-invert:  ;
  --tw-backdrop-opacity:  ;
  --tw-backdrop-saturate:  ;
  --tw-backdrop-sepia:  ;
  --tw-contain-size:  ;
  --tw-contain-layout:  ;
  --tw-contain-paint:  ;
  --tw-contain-style:  ;
}

::backdrop {
  --tw-border-spacing-x: 0;
  --tw-border-spacing-y: 0;
  --tw-translate-x: 0;
  --tw-translate-y: 0;
  --tw-rotate: 0;
  --tw-skew-x: 0;
  --tw-skew-y: 0;
  --tw-scale-x: 1;
  --tw-scale-y: 1;
  --tw-pan-x:  ;
  --tw-pan-y:  ;
  --tw-pinch-zoom:  ;
  --tw-scroll-snap-strictness: proximity;
  --tw-gradient-from-position:  ;
  --tw-gradient-via-position:  ;
  --tw-gradient-to-position:  ;
  --tw-ordinal:  ;
  --tw-slashed-zero:  ;
  --tw-numeric-figure:  ;
  --tw-numeric-spacing:  ;
  --tw-numeric-fraction:  ;
  --tw-ring-inset:  ;
  --tw-ring-offset-width: 0px;
  --tw-ring-offset-color: #fff;
  --tw-ring-color: rgb(59 130 246 / 0.5);
  --tw-ring-offset-shadow: 0 0 #0000;
  --tw-ring-shadow: 0 0 #0000;
  --tw-shadow: 0 0 #0000;
  --tw-shadow-colored: 0 0 #0000;
  --tw-blur:  ;
  --tw-brightness:  ;
  --tw-contrast:  ;
  --tw-grayscale:  ;
  --tw-hue-rotate:  ;
  --tw-invert:  ;
  --tw-saturate:  ;
  --tw-sepia:  ;
  --tw-drop-shadow:  ;
  --tw-backdrop-blur:  ;
  --tw-backdrop-brightness:  ;
  --tw-backdrop-contrast:  ;
  --tw-backdrop-grayscale:  ;
  --tw-backdrop-hue-rotate:  ;
  --tw-backdrop-invert:  ;
  --tw-backdrop-opacity:  ;
  --tw-backdrop-saturate:  ;
  --tw-backdrop-sepia:  ;
  --tw-contain-size:  ;
  --tw-contain-layout:  ;
  --tw-contain-paint:  ;
  --tw-contain-style:  ;
}

/*
! tailwindcss v3.4.19 | MIT License | https://tailwindcss.com
*/

/*
1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
*/

*,
::before,
::after {
  box-sizing: border-box;
  /* 1 */
  border-width: 0;
  /* 2 */
  border-style: solid;
  /* 2 */
  border-color: #e5e7eb;
  /* 2 */
}

::before,
::after {
  --tw-content: '';
}

/*
1. Use a consistent sensible line-height in all browsers.
2. Prevent adjustments of font size after orientation changes in iOS.
3. Use a more readable tab size.
4. Use the user's configured `sans` font-family by default.
5. Use the user's configured `sans` font-feature-settings by default.
6. Use the user's configured `sans` font-variation-settings by default.
7. Disable tap highlights on iOS
*/

html,
:host {
  line-height: 1.5;
  /* 1 */
  -webkit-text-size-adjust: 100%;
  /* 2 */
  -moz-tab-size: 4;
  /* 3 */
  -o-tab-size: 4;
     tab-size: 4;
  /* 3 */
  font-family: ui-sans-serif, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;
  /* 4 */
  font-feature-settings: normal;
  /* 5 */
  font-variation-settings: normal;
  /* 6 */
  -webkit-tap-highlight-color: transparent;
  /* 7 */
}

/*
1. Remove the margin in all browsers.
2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
*/

body {
  margin: 0;
  /* 1 */
  line-height: inherit;
  /* 2 */
}

/*
1. Add the correct height in Firefox.
2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
3. Ensure horizontal rules are visible by default.
*/

hr {
  height: 0;
  /* 1 */
  color: inherit;
  /* 2 */
  border-top-width: 1px;
  /* 3 */
}

/*
Add the correct text decoration in Chrome, Edge, and Safari.
*/

abbr:where([title]) {
  -webkit-text-decoration: underline dotted;
          text-decoration: underline dotted;
}

/*
Remove the default font size and weight for headings.
*/

h1,
h2,
h3,
h4,
h5,
h6 {
  font-size: inherit;
  font-weight: inherit;
}

/*
Reset links to optimize for opt-in styling instead of opt-out.
*/

a {
  color: inherit;
  text-decoration: inherit;
}

/*
Add the correct font weight in Edge and Safari.
*/

b,
strong {
  font-weight: bolder;
}

/*
1. Use the user's configured `mono` font-family by default.
2. Use the user's configured `mono` font-feature-settings by default.
3. Use the user's configured `mono` font-variation-settings by default.
4. Correct the odd `em` font sizing in all browsers.
*/

code,
kbd,
samp,
pre {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace;
  /* 1 */
  font-feature-settings: normal;
  /* 2 */
  font-variation-settings: normal;
  /* 3 */
  font-size: 1em;
  /* 4 */
}

/*
Add the correct font size in all browsers.
*/

small {
  font-size: 80%;
}

/*
Prevent `sub` and `sup` elements from affecting the line height in all browsers.
*/

sub,
sup {
  font-size: 75%;
  line-height: 0;
  position: relative;
  vertical-align: baseline;
}

sub {
  bottom: -0.25em;
}

sup {
  top: -0.5em;
}

/*
1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
3. Remove gaps between table borders by default.
*/

table {
  text-indent: 0;
  /* 1 */
  border-color: inherit;
  /* 2 */
  border-collapse: collapse;
  /* 3 */
}

/*
1. Change the font styles in all browsers.
2. Remove the margin in Firefox and Safari.
3. Remove default padding in all browsers.
*/

button,
input,
optgroup,
select,
textarea {
  font-family: inherit;
  /* 1 */
  font-feature-settings: inherit;
  /* 1 */
  font-variation-settings: inherit;
  /* 1 */
  font-size: 100%;
  /* 1 */
  font-weight: inherit;
  /* 1 */
  line-height: inherit;
  /* 1 */
  letter-spacing: inherit;
  /* 1 */
  color: inherit;
  /* 1 */
  margin: 0;
  /* 2 */
  padding: 0;
  /* 3 */
}

/*
Remove the inheritance of text transform in Edge and Firefox.
*/

button,
select {
  text-transform: none;
}

/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Remove default button styles.
*/

button,
input:where([type='button']),
input:where([type='reset']),
input:where([type='submit']) {
  -webkit-appearance: button;
  /* 1 */
  background-color: transparent;
  /* 2 */
  background-image: none;
  /* 2 */
}

/*
Use the modern Firefox focus style for all focusable elements.
*/

:-moz-focusring {
  outline: auto;
}

/*
Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
*/

:-moz-ui-invalid {
  box-shadow: none;
}

/*
Add the correct vertical alignment in Chrome and Firefox.
*/

progress {
  vertical-align: baseline;
}

/*
Correct the cursor style of increment and decrement buttons in Safari.
*/

::-webkit-inner-spin-button,
::-webkit-outer-spin-button {
  height: auto;
}

/*
1. Correct the odd appearance in Chrome and Safari.
2. Correct the outline style in Safari.
*/

[type='search'] {
  -webkit-appearance: textfield;
  /* 1 */
  outline-offset: -2px;
  /* 2 */
}

/*
Remove the inner padding in Chrome and Safari on macOS.
*/

::-webkit-search-decoration {
  -webkit-appearance: none;
}

/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Change font properties to `inherit` in Safari.
*/

::-webkit-file-upload-button {
  -webkit-appearance: button;
  /* 1 */
  font: inherit;
  /* 2 */
}

/*
Add the correct display in Chrome and Safari.
*/

summary {
  display: list-item;
}

/*
Removes the default spacing and border for appropriate elements.
*/

blockquote,
dl,
dd,
h1,
h2,
h3,
h4,
h5,
h6,
hr,
figure,
p,
pre {
  margin: 0;
}

fieldset {
  margin: 0;
  padding: 0;
}

legend {
  padding: 0;
}

ol,
ul,
menu {
  list-style: none;
  margin: 0;
  padding: 0;
}

/*
Reset default styling for dialogs.
*/

dialog {
  padding: 0;
}

/*
Prevent resizing textareas horizontally by default.
*/

textarea {
  resize: vertical;
}

/*
1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
2. Set the default placeholder color to the user's configured gray 400 color.
*/

input::-moz-placeholder, textarea::-moz-placeholder {
  opacity: 1;
  /* 1 */
  color: #9ca3af;
  /* 2 */
}

input::placeholder,
textarea::placeholder {
  opacity: 1;
  /* 1 */
  color: #9ca3af;
  /* 2 */
}

/*
Set the default cursor for buttons.
*/

button,
[role="button"] {
  cursor: pointer;
}

/*
Make sure disabled buttons don't get the pointer cursor.
*/

:disabled {
  cursor: default;
}

/*
1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
   This can trigger a poorly considered lint error in some tools but is included by design.
*/

img,
svg,
video,
canvas,
audio,
iframe,
embed,
object {
  display: block;
  /* 1 */
  vertical-align: middle;
  /* 2 */
}

/*
Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
*/

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

/* Make elements with the HTML hidden attribute stay hidden by default */

[hidden]:where(:not([hidden="until-found"])) {
  display: none;
}

:root {
  /* Typography */
  --font-display: "Clash Display", sans-serif;
  --font-body: "Satoshi", sans-serif;
  --font-jetbrains: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
  /* Fluid Typography Scale */
  --text-display-xl: clamp(3rem, 8vw, 6rem);
  --text-display-lg: clamp(2.5rem, 6vw, 4.5rem);
  --text-display-md: clamp(2rem, 4vw, 3rem);
  --text-display-sm: clamp(1.5rem, 3vw, 2rem);
  --text-body-lg: clamp(1.125rem, 1.5vw, 1.25rem);
  --text-table: clamp(0.9rem, 1vw, 0.95em);
  --text-body: clamp(1rem, 1.2vw, 1.125rem);
  --text-body-sm: clamp(0.875rem, 1vw, 0.9375rem);
  /* Fluid Spacing */
  --space-section: clamp(4rem, 10vw, 8rem);
  --space-block: clamp(2rem, 5vw, 4rem);
  --space-element: clamp(1rem, 2vw, 1.5rem);
  /* Project Detail hero envelope */
  --hero-h: clamp(640px, 92vh, 860px);
  --hero-image-min-h: clamp(180px, 26vh, 260px);
  --background: 0 0% 100%;
  --foreground: 222.2 84% 4.9%;
  --card: 0 0% 100%;
  --card-foreground: 222.2 84% 4.9%;
  --popover: 0 0% 100%;
  --popover-foreground: 222.2 84% 4.9%;
  --primary: 222.2 47.4% 11.2%;
  --primary-foreground: 210 40% 98%;
  --secondary: 210 40% 96.1%;
  --secondary-foreground: 222.2 47.4% 11.2%;
  --muted: 210 40% 96.1%;
  /* Lightness 44 → 4.87:1 on --muted (WCAG AA pass). Was 46.9 (4.34 — fail). */
  --muted-foreground: 215.4 16.3% 44%;
  --accent: 210 40% 96.1%;
  --accent-foreground: 222.2 47.4% 11.2%;
  --destructive: 0 84.2% 60.2%;
  --destructive-foreground: 210 40% 98%;
  --border: 214.3 31.8% 91.4%;
  --input: 214.3 31.8% 91.4%;
  --ring: 222.2 84% 4.9%;
  --radius: 0.5rem;
  --sidebar-background: 0 0% 98%;
  --sidebar-foreground: 240 5.3% 26.1%;
  --sidebar-primary: 240 5.9% 10%;
  --sidebar-primary-foreground: 0 0% 98%;
  --sidebar-accent: 240 4.8% 95.9%;
  --sidebar-accent-foreground: 240 5.9% 10%;
  --sidebar-border: 220 13% 91%;
  --sidebar-ring: 217.2 91.2% 59.8%;
  --chart-1: 217 10% 64%;
  --chart-2: 215 20% 65%;
  --chart-3: 215 16% 46%;
  --chart-4: 219 8% 46%;
  --chart-5: 215 19% 34%;
  --sidebar: 210 40% 98%;
  --font-sans:
      "DM Sans", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
      Arial, "Noto Sans", sans-serif;
  --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
  --font-mono:
      "SF Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
  --shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
  --shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
  --shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1);
  --shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1);
  --shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 2px 4px -1px hsl(0 0% 0% / 0.1);
  --shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 4px 6px -1px hsl(0 0% 0% / 0.1);
  --shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 8px 10px -1px hsl(0 0% 0% / 0.1);
  --shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25);
  --tracking-normal: 0em;
  --spacing: 0.25rem;
}

.dark {
  --background: 222.2 84% 4.9%;
  --foreground: 210 40% 98%;
  --card: 222.2 84% 4.9%;
  --card-foreground: 210 40% 98%;
  --popover: 222.2 84% 4.9%;
  --popover-foreground: 210 40% 98%;
  --primary: 210 40% 98%;
  --primary-foreground: 222.2 47.4% 11.2%;
  --secondary: 217.2 32.6% 17.5%;
  --secondary-foreground: 210 40% 98%;
  --muted: 217.2 32.6% 17.5%;
  --muted-foreground: 215 20.2% 65.1%;
  --accent: 217.2 32.6% 17.5%;
  --accent-foreground: 210 40% 98%;
  --destructive: 0 62.8% 30.6%;
  --destructive-foreground: 210 40% 98%;
  --border: 217.2 32.6% 17.5%;
  --input: 217.2 32.6% 17.5%;
  --ring: 212.7 26.8% 83.9%;
  --sidebar-background: 240 5.9% 10%;
  --sidebar-foreground: 240 4.8% 95.9%;
  --sidebar-primary: 224.3 76.3% 48%;
  --sidebar-primary-foreground: 0 0% 100%;
  --sidebar-accent: 240 3.7% 15.9%;
  --sidebar-accent-foreground: 240 4.8% 95.9%;
  --sidebar-border: 240 3.7% 15.9%;
  --sidebar-ring: 217.2 91.2% 59.8%;
  --chart-1: 215 12% 83%;
  --chart-2: 212 26% 83%;
  --chart-3: 215 20% 65%;
  --chart-4: 217 10% 64%;
  --chart-5: 215 16% 46%;
  --sidebar: 217 32% 17%;
  --shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
  --shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
  --shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1);
  --shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1);
  --shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 2px 4px -1px hsl(0 0% 0% / 0.1);
  --shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 4px 6px -1px hsl(0 0% 0% / 0.1);
  --shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 8px 10px -1px hsl(0 0% 0% / 0.1);
  --shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25);
}

@media (min-width: 1024px) {
  :root {
    --hero-h: clamp(640px, 88vh, 920px);
    --hero-image-min-h: clamp(280px, 38vh, 420px);
  }
}

/* WCAG 2.2 — visible focus on every interactive element. */

:focus-visible {
  outline: 2px solid hsl(var(--ring));
  outline-offset: 2px;
  border-radius: inherit;
}

/* Opt-in dark scope (case studies, code blocks). Scoped only — never global. */

.dark {
  color-scheme: dark;
}

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

* {
  border-color: hsl(var(--border));
}

html {
  font-family: var(--font-body);
  /* Pin the UA palette (form controls, scrollbars, autofill) to light.
       The site has no theme switcher and must not be inverted by a client
       device set to "Dark". Opt-in dark surfaces re-declare this below. */
  color-scheme: light;
  /* Keep focus targets and anchor jumps clear of the floating bottom nav. */
  scroll-padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 5rem);
  scroll-padding-top: 1rem;
}

body {
  background-color: hsl(var(--background));
  color: hsl(var(--foreground));
  font-size: var(--text-body);
  line-height: 1.6;
}

h1,
  h2,
  h3,
  h4,
  h5,
  h6 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.02em;
}

h1 {
  font-size: var(--text-display-xl);
}

h2 {
  font-size: var(--text-display-lg);
}

h3 {
  font-size: var(--text-display-md);
}

h4 {
  font-size: var(--text-display-sm);
}

.container {
  width: 100%;
  margin-right: auto;
  margin-left: auto;
  padding-right: 2rem;
  padding-left: 2rem;
}

@media (min-width: 1400px) {
  .container {
    max-width: 1400px;
  }
}

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

.pointer-events-none {
  pointer-events: none;
}

.\!visible {
  visibility: visible !important;
}

.visible {
  visibility: visible;
}

.invisible {
  visibility: hidden;
}

.collapse {
  visibility: collapse;
}

.static {
  position: static;
}

.fixed {
  position: fixed;
}

.absolute {
  position: absolute;
}

.relative {
  position: relative;
}

.sticky {
  position: sticky;
}

.inset-0 {
  inset: 0px;
}

.inset-y-0 {
  top: 0px;
  bottom: 0px;
}

.bottom-0 {
  bottom: 0px;
}

.bottom-full {
  bottom: 100%;
}

.left-0 {
  left: 0px;
}

.left-1\/2 {
  left: 50%;
}

.left-3 {
  left: 0.75rem;
}

.left-4 {
  left: 1rem;
}

.left-\[3px\] {
  left: 3px;
}

.left-\[88px\] {
  left: 88px;
}

.left-\[calc\(100\%-0\.875rem-3px\)\] {
  left: calc(100% - 0.875rem - 3px);
}

.right-0 {
  right: 0px;
}

.right-3 {
  right: 0.75rem;
}

.top-0 {
  top: 0px;
}

.top-1\/2 {
  top: 50%;
}

.top-16 {
  top: 4rem;
}

.top-24 {
  top: 6rem;
}

.top-3 {
  top: 0.75rem;
}

.top-4 {
  top: 1rem;
}

.z-10 {
  z-index: 10;
}

.z-40 {
  z-index: 40;
}

.z-50 {
  z-index: 50;
}

.z-\[60\] {
  z-index: 60;
}

.z-\[98\] {
  z-index: 98;
}

.z-\[99\] {
  z-index: 99;
}

.order-1 {
  order: 1;
}

.order-2 {
  order: 2;
}

.-mx-4 {
  margin-left: -1rem;
  margin-right: -1rem;
}

.-mx-6 {
  margin-left: -1.5rem;
  margin-right: -1.5rem;
}

.mx-1 {
  margin-left: 0.25rem;
  margin-right: 0.25rem;
}

.mx-auto {
  margin-left: auto;
  margin-right: auto;
}

.my-10 {
  margin-top: 2.5rem;
  margin-bottom: 2.5rem;
}

.my-12 {
  margin-top: 3rem;
  margin-bottom: 3rem;
}

.my-2 {
  margin-top: 0.5rem;
  margin-bottom: 0.5rem;
}

.my-6 {
  margin-top: 1.5rem;
  margin-bottom: 1.5rem;
}

.my-8 {
  margin-top: 2rem;
  margin-bottom: 2rem;
}

.mb-1 {
  margin-bottom: 0.25rem;
}

.mb-10 {
  margin-bottom: 2.5rem;
}

.mb-16 {
  margin-bottom: 4rem;
}

.mb-2 {
  margin-bottom: 0.5rem;
}

.mb-20 {
  margin-bottom: 5rem;
}

.mb-3 {
  margin-bottom: 0.75rem;
}

.mb-4 {
  margin-bottom: 1rem;
}

.mb-6 {
  margin-bottom: 1.5rem;
}

.mb-8 {
  margin-bottom: 2rem;
}

.ml-0\.5 {
  margin-left: 0.125rem;
}

.ml-1 {
  margin-left: 0.25rem;
}

.ml-1\.5 {
  margin-left: 0.375rem;
}

.ml-2 {
  margin-left: 0.5rem;
}

.mr-1 {
  margin-right: 0.25rem;
}

.mr-2 {
  margin-right: 0.5rem;
}

.mr-\[0\.3em\] {
  margin-right: 0.3em;
}

.mt-1 {
  margin-top: 0.25rem;
}

.mt-10 {
  margin-top: 2.5rem;
}

.mt-12 {
  margin-top: 3rem;
}

.mt-16 {
  margin-top: 4rem;
}

.mt-2 {
  margin-top: 0.5rem;
}

.mt-3 {
  margin-top: 0.75rem;
}

.mt-4 {
  margin-top: 1rem;
}

.mt-5 {
  margin-top: 1.25rem;
}

.mt-6 {
  margin-top: 1.5rem;
}

.mt-8 {
  margin-top: 2rem;
}

.line-clamp-2 {
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}

.line-clamp-3 {
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
}

.block {
  display: block;
}

.inline-block {
  display: inline-block;
}

.\!inline {
  display: inline !important;
}

.inline {
  display: inline;
}

.flex {
  display: flex;
}

.inline-flex {
  display: inline-flex;
}

.table {
  display: table;
}

.grid {
  display: grid;
}

.contents {
  display: contents;
}

.hidden {
  display: none;
}

.aspect-\[4\/3\] {
  aspect-ratio: 4/3;
}

.aspect-\[4\/5\] {
  aspect-ratio: 4/5;
}

.h-0\.5 {
  height: 0.125rem;
}

.h-1 {
  height: 0.25rem;
}

.h-10 {
  height: 2.5rem;
}

.h-16 {
  height: 4rem;
}

.h-2 {
  height: 0.5rem;
}

.h-3 {
  height: 0.75rem;
}

.h-3\.5 {
  height: 0.875rem;
}

.h-4 {
  height: 1rem;
}

.h-5 {
  height: 1.25rem;
}

.h-9 {
  height: 2.25rem;
}

.h-auto {
  height: auto;
}

.h-full {
  height: 100%;
}

.h-px {
  height: 1px;
}

.h-screen {
  height: 100vh;
}

.min-h-\[180px\] {
  min-height: 180px;
}

.min-h-\[2\.5rem\] {
  min-height: 2.5rem;
}

.min-h-full {
  min-height: 100%;
}

.min-h-screen {
  min-height: 100vh;
}

.w-1 {
  width: 0.25rem;
}

.w-10 {
  width: 2.5rem;
}

.w-16 {
  width: 4rem;
}

.w-2 {
  width: 0.5rem;
}

.w-20 {
  width: 5rem;
}

.w-24 {
  width: 6rem;
}

.w-28 {
  width: 7rem;
}

.w-3 {
  width: 0.75rem;
}

.w-3\.5 {
  width: 0.875rem;
}

.w-4 {
  width: 1rem;
}

.w-5 {
  width: 1.25rem;
}

.w-64 {
  width: 16rem;
}

.w-9 {
  width: 2.25rem;
}

.w-\[200px\] {
  width: 200px;
}

.w-\[3ch\] {
  width: 3ch;
}

.w-\[64px\] {
  width: 64px;
}

.w-\[70\%\] {
  width: 70%;
}

.w-auto {
  width: auto;
}

.w-full {
  width: 100%;
}

.w-px {
  width: 1px;
}

.min-w-0 {
  min-width: 0px;
}

.min-w-\[100px\] {
  min-width: 100px;
}

.min-w-\[260px\] {
  min-width: 260px;
}

.max-w-2xl {
  max-width: 42rem;
}

.max-w-3xl {
  max-width: 48rem;
}

.max-w-4xl {
  max-width: 56rem;
}

.max-w-\[68ch\] {
  max-width: 68ch;
}

.max-w-\[95vw\] {
  max-width: 95vw;
}

.max-w-lg {
  max-width: 32rem;
}

.max-w-md {
  max-width: 28rem;
}

.max-w-xl {
  max-width: 36rem;
}

.flex-1 {
  flex: 1 1 0%;
}

.flex-shrink-0 {
  flex-shrink: 0;
}

.shrink-0 {
  flex-shrink: 0;
}

.caption-top {
  caption-side: top;
}

.-translate-x-1\/2 {
  --tw-translate-x: -50%;
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}

.-translate-y-1\/2 {
  --tw-translate-y: -50%;
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}

.transform {
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}

@keyframes pulse {
  50% {
    opacity: .5;
  }
}

.animate-pulse {
  animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}

.cursor-pointer {
  cursor: pointer;
}

.select-none {
  -webkit-user-select: none;
     -moz-user-select: none;
          user-select: none;
}

.resize {
  resize: both;
}

.scroll-mt-24 {
  scroll-margin-top: 6rem;
}

.list-decimal {
  list-style-type: decimal;
}

.list-none {
  list-style-type: none;
}

.grid-cols-1 {
  grid-template-columns: repeat(1, minmax(0, 1fr));
}

.grid-cols-\[1fr_auto_1fr\] {
  grid-template-columns: 1fr auto 1fr;
}

.grid-cols-\[3ch_1fr\] {
  grid-template-columns: 3ch 1fr;
}

.grid-cols-\[auto_1fr\] {
  grid-template-columns: auto 1fr;
}

.flex-row-reverse {
  flex-direction: row-reverse;
}

.flex-col {
  flex-direction: column;
}

.flex-wrap {
  flex-wrap: wrap;
}

.items-start {
  align-items: flex-start;
}

.items-end {
  align-items: flex-end;
}

.items-center {
  align-items: center;
}

.items-baseline {
  align-items: baseline;
}

.justify-center {
  justify-content: center;
}

.justify-between {
  justify-content: space-between;
}

.gap-1 {
  gap: 0.25rem;
}

.gap-1\.5 {
  gap: 0.375rem;
}

.gap-10 {
  gap: 2.5rem;
}

.gap-12 {
  gap: 3rem;
}

.gap-16 {
  gap: 4rem;
}

.gap-2 {
  gap: 0.5rem;
}

.gap-2\.5 {
  gap: 0.625rem;
}

.gap-3 {
  gap: 0.75rem;
}

.gap-4 {
  gap: 1rem;
}

.gap-6 {
  gap: 1.5rem;
}

.gap-8 {
  gap: 2rem;
}

.gap-x-10 {
  -moz-column-gap: 2.5rem;
       column-gap: 2.5rem;
}

.gap-x-3 {
  -moz-column-gap: 0.75rem;
       column-gap: 0.75rem;
}

.gap-x-4 {
  -moz-column-gap: 1rem;
       column-gap: 1rem;
}

.gap-x-5 {
  -moz-column-gap: 1.25rem;
       column-gap: 1.25rem;
}

.gap-y-1 {
  row-gap: 0.25rem;
}

.gap-y-2 {
  row-gap: 0.5rem;
}

.gap-y-6 {
  row-gap: 1.5rem;
}

.space-y-0 > :not([hidden]) ~ :not([hidden]) {
  --tw-space-y-reverse: 0;
  margin-top: calc(0px * calc(1 - var(--tw-space-y-reverse)));
  margin-bottom: calc(0px * var(--tw-space-y-reverse));
}

.space-y-1 > :not([hidden]) ~ :not([hidden]) {
  --tw-space-y-reverse: 0;
  margin-top: calc(0.25rem * calc(1 - var(--tw-space-y-reverse)));
  margin-bottom: calc(0.25rem * var(--tw-space-y-reverse));
}

.space-y-12 > :not([hidden]) ~ :not([hidden]) {
  --tw-space-y-reverse: 0;
  margin-top: calc(3rem * calc(1 - var(--tw-space-y-reverse)));
  margin-bottom: calc(3rem * var(--tw-space-y-reverse));
}

.space-y-16 > :not([hidden]) ~ :not([hidden]) {
  --tw-space-y-reverse: 0;
  margin-top: calc(4rem * calc(1 - var(--tw-space-y-reverse)));
  margin-bottom: calc(4rem * var(--tw-space-y-reverse));
}

.space-y-2 > :not([hidden]) ~ :not([hidden]) {
  --tw-space-y-reverse: 0;
  margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));
  margin-bottom: calc(0.5rem * var(--tw-space-y-reverse));
}

.space-y-3 > :not([hidden]) ~ :not([hidden]) {
  --tw-space-y-reverse: 0;
  margin-top: calc(0.75rem * calc(1 - var(--tw-space-y-reverse)));
  margin-bottom: calc(0.75rem * var(--tw-space-y-reverse));
}

.space-y-5 > :not([hidden]) ~ :not([hidden]) {
  --tw-space-y-reverse: 0;
  margin-top: calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));
  margin-bottom: calc(1.25rem * var(--tw-space-y-reverse));
}

.space-y-6 > :not([hidden]) ~ :not([hidden]) {
  --tw-space-y-reverse: 0;
  margin-top: calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));
  margin-bottom: calc(1.5rem * var(--tw-space-y-reverse));
}

.space-y-8 > :not([hidden]) ~ :not([hidden]) {
  --tw-space-y-reverse: 0;
  margin-top: calc(2rem * calc(1 - var(--tw-space-y-reverse)));
  margin-bottom: calc(2rem * var(--tw-space-y-reverse));
}

.divide-y > :not([hidden]) ~ :not([hidden]) {
  --tw-divide-y-reverse: 0;
  border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse)));
  border-bottom-width: calc(1px * var(--tw-divide-y-reverse));
}

.divide-border > :not([hidden]) ~ :not([hidden]) {
  border-color: hsl(var(--border));
}

.self-start {
  align-self: flex-start;
}

.self-center {
  align-self: center;
}

.self-stretch {
  align-self: stretch;
}

.justify-self-start {
  justify-self: start;
}

.justify-self-end {
  justify-self: end;
}

.overflow-hidden {
  overflow: hidden;
}

.overflow-x-auto {
  overflow-x: auto;
}

.overflow-y-auto {
  overflow-y: auto;
}

.truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.whitespace-nowrap {
  white-space: nowrap;
}

.whitespace-pre {
  white-space: pre;
}

.whitespace-pre-line {
  white-space: pre-line;
}

.whitespace-pre-wrap {
  white-space: pre-wrap;
}

.rounded {
  border-radius: 0.25rem;
}

.rounded-2xl {
  border-radius: 1rem;
}

.rounded-full {
  border-radius: 9999px;
}

.rounded-lg {
  border-radius: var(--radius);
}

.rounded-md {
  border-radius: calc(var(--radius) - 2px);
}

.rounded-none {
  border-radius: 0px;
}

.rounded-sm {
  border-radius: calc(var(--radius) - 4px);
}

.border {
  border-width: 1px;
}

.border-y {
  border-top-width: 1px;
  border-bottom-width: 1px;
}

.border-b {
  border-bottom-width: 1px;
}

.border-l-2 {
  border-left-width: 2px;
}

.border-t {
  border-top-width: 1px;
}

.border-background\/10 {
  border-color: hsl(var(--background) / 0.1);
}

.border-background\/20 {
  border-color: hsl(var(--background) / 0.2);
}

.border-border {
  border-color: hsl(var(--border));
}

.border-foreground {
  border-color: hsl(var(--foreground));
}

.border-foreground\/10 {
  border-color: hsl(var(--foreground) / 0.1);
}

.border-foreground\/20 {
  border-color: hsl(var(--foreground) / 0.2);
}

.border-muted-foreground\/20 {
  border-color: hsl(var(--muted-foreground) / 0.2);
}

.border-muted-foreground\/25 {
  border-color: hsl(var(--muted-foreground) / 0.25);
}

.border-l-foreground {
  border-left-color: hsl(var(--foreground));
}

.border-l-foreground\/40 {
  border-left-color: hsl(var(--foreground) / 0.4);
}

.border-l-muted-foreground\/40 {
  border-left-color: hsl(var(--muted-foreground) / 0.4);
}

.bg-background {
  background-color: hsl(var(--background));
}

.bg-background\/20 {
  background-color: hsl(var(--background) / 0.2);
}

.bg-background\/70 {
  background-color: hsl(var(--background) / 0.7);
}

.bg-background\/90 {
  background-color: hsl(var(--background) / 0.9);
}

.bg-background\/95 {
  background-color: hsl(var(--background) / 0.95);
}

.bg-black {
  --tw-bg-opacity: 1;
  background-color: rgb(0 0 0 / var(--tw-bg-opacity, 1));
}

.bg-border {
  background-color: hsl(var(--border));
}

.bg-foreground {
  background-color: hsl(var(--foreground));
}

.bg-foreground\/20 {
  background-color: hsl(var(--foreground) / 0.2);
}

.bg-foreground\/5 {
  background-color: hsl(var(--foreground) / 0.05);
}

.bg-foreground\/80 {
  background-color: hsl(var(--foreground) / 0.8);
}

.bg-foreground\/90 {
  background-color: hsl(var(--foreground) / 0.9);
}

.bg-muted {
  background-color: hsl(var(--muted));
}

.bg-muted-foreground {
  background-color: hsl(var(--muted-foreground));
}

.bg-muted\/10 {
  background-color: hsl(var(--muted) / 0.1);
}

.bg-muted\/20 {
  background-color: hsl(var(--muted) / 0.2);
}

.bg-muted\/30 {
  background-color: hsl(var(--muted) / 0.3);
}

.bg-muted\/40 {
  background-color: hsl(var(--muted) / 0.4);
}

.bg-muted\/50 {
  background-color: hsl(var(--muted) / 0.5);
}

.bg-muted\/60 {
  background-color: hsl(var(--muted) / 0.6);
}

.bg-transparent {
  background-color: transparent;
}

.bg-white {
  --tw-bg-opacity: 1;
  background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));
}

.bg-white\/40 {
  background-color: rgb(255 255 255 / 0.4);
}

.bg-gradient-to-t {
  background-image: linear-gradient(to top, var(--tw-gradient-stops));
}

.from-black\/70 {
  --tw-gradient-from: rgb(0 0 0 / 0.7) var(--tw-gradient-from-position);
  --tw-gradient-to: rgb(0 0 0 / 0) var(--tw-gradient-to-position);
  --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
}

.from-black\/80 {
  --tw-gradient-from: rgb(0 0 0 / 0.8) var(--tw-gradient-from-position);
  --tw-gradient-to: rgb(0 0 0 / 0) var(--tw-gradient-to-position);
  --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
}

.via-black\/20 {
  --tw-gradient-to: rgb(0 0 0 / 0)  var(--tw-gradient-to-position);
  --tw-gradient-stops: var(--tw-gradient-from), rgb(0 0 0 / 0.2) var(--tw-gradient-via-position), var(--tw-gradient-to);
}

.via-black\/30 {
  --tw-gradient-to: rgb(0 0 0 / 0)  var(--tw-gradient-to-position);
  --tw-gradient-stops: var(--tw-gradient-from), rgb(0 0 0 / 0.3) var(--tw-gradient-via-position), var(--tw-gradient-to);
}

.to-black\/10 {
  --tw-gradient-to: rgb(0 0 0 / 0.1) var(--tw-gradient-to-position);
}

.to-transparent {
  --tw-gradient-to: transparent var(--tw-gradient-to-position);
}

.object-contain {
  -o-object-fit: contain;
     object-fit: contain;
}

.object-cover {
  -o-object-fit: cover;
     object-fit: cover;
}

.object-center {
  -o-object-position: center;
     object-position: center;
}

.p-0 {
  padding: 0px;
}

.p-1 {
  padding: 0.25rem;
}

.p-1\.5 {
  padding: 0.375rem;
}

.p-2 {
  padding: 0.5rem;
}

.p-4 {
  padding: 1rem;
}

.p-5 {
  padding: 1.25rem;
}

.p-6 {
  padding: 1.5rem;
}

.p-8 {
  padding: 2rem;
}

.px-1\.5 {
  padding-left: 0.375rem;
  padding-right: 0.375rem;
}

.px-2 {
  padding-left: 0.5rem;
  padding-right: 0.5rem;
}

.px-3 {
  padding-left: 0.75rem;
  padding-right: 0.75rem;
}

.px-4 {
  padding-left: 1rem;
  padding-right: 1rem;
}

.px-5 {
  padding-left: 1.25rem;
  padding-right: 1.25rem;
}

.px-6 {
  padding-left: 1.5rem;
  padding-right: 1.5rem;
}

.py-0\.5 {
  padding-top: 0.125rem;
  padding-bottom: 0.125rem;
}

.py-1 {
  padding-top: 0.25rem;
  padding-bottom: 0.25rem;
}

.py-1\.5 {
  padding-top: 0.375rem;
  padding-bottom: 0.375rem;
}

.py-12 {
  padding-top: 3rem;
  padding-bottom: 3rem;
}

.py-16 {
  padding-top: 4rem;
  padding-bottom: 4rem;
}

.py-2 {
  padding-top: 0.5rem;
  padding-bottom: 0.5rem;
}

.py-2\.5 {
  padding-top: 0.625rem;
  padding-bottom: 0.625rem;
}

.py-24 {
  padding-top: 6rem;
  padding-bottom: 6rem;
}

.py-3 {
  padding-top: 0.75rem;
  padding-bottom: 0.75rem;
}

.py-4 {
  padding-top: 1rem;
  padding-bottom: 1rem;
}

.py-6 {
  padding-top: 1.5rem;
  padding-bottom: 1.5rem;
}

.py-\[var\(--space-block\)\] {
  padding-top: var(--space-block);
  padding-bottom: var(--space-block);
}

.py-\[var\(--space-section\)\] {
  padding-top: var(--space-section);
  padding-bottom: var(--space-section);
}

.pb-1 {
  padding-bottom: 0.25rem;
}

.pb-2 {
  padding-bottom: 0.5rem;
}

.pb-28 {
  padding-bottom: 7rem;
}

.pb-3 {
  padding-bottom: 0.75rem;
}

.pb-6 {
  padding-bottom: 1.5rem;
}

.pb-8 {
  padding-bottom: 2rem;
}

.pb-\[calc\(env\(safe-area-inset-bottom\2c 0px\)\+1\.5rem\+2\.5rem\+1\.5rem\)\] {
  padding-bottom: calc(env(safe-area-inset-bottom,0px) + 1.5rem + 2.5rem + 1.5rem);
}

.pb-\[var\(--space-block\)\] {
  padding-bottom: var(--space-block);
}

.pb-\[var\(--space-section\)\] {
  padding-bottom: var(--space-section);
}

.pl-4 {
  padding-left: 1rem;
}

.pl-5 {
  padding-left: 1.25rem;
}

.pl-6 {
  padding-left: 1.5rem;
}

.pl-8 {
  padding-left: 2rem;
}

.pl-9 {
  padding-left: 2.25rem;
}

.pr-2 {
  padding-right: 0.5rem;
}

.pr-4 {
  padding-right: 1rem;
}

.pr-9 {
  padding-right: 2.25rem;
}

.pt-0 {
  padding-top: 0px;
}

.pt-0\.5 {
  padding-top: 0.125rem;
}

.pt-1 {
  padding-top: 0.25rem;
}

.pt-1\.5 {
  padding-top: 0.375rem;
}

.pt-10 {
  padding-top: 2.5rem;
}

.pt-12 {
  padding-top: 3rem;
}

.pt-16 {
  padding-top: 4rem;
}

.pt-4 {
  padding-top: 1rem;
}

.pt-6 {
  padding-top: 1.5rem;
}

.pt-8 {
  padding-top: 2rem;
}

.pt-\[var\(--space-block\)\] {
  padding-top: var(--space-block);
}

.pt-\[var\(--space-section\)\] {
  padding-top: var(--space-section);
}

.text-left {
  text-align: left;
}

.text-center {
  text-align: center;
}

.text-right {
  text-align: right;
}

.align-top {
  vertical-align: top;
}

.font-display {
  font-family: Clash Display, sans-serif;
}

.font-jetbrains {
  font-family: JetBrains Mono, ui-monospace, SFMono-Regular, Menlo, Consolas, Liberation Mono, monospace;
}

.font-mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace;
}

.text-2xl {
  font-size: 1.5rem;
  line-height: 2rem;
}

.text-\[0\.65rem\] {
  font-size: 0.65rem;
}

.text-\[0\.7em\] {
  font-size: 0.7em;
}

.text-\[10px\] {
  font-size: 10px;
}

.text-\[11px\] {
  font-size: 11px;
}

.text-\[length\:var\(--text-display-sm\)\] {
  font-size: var(--text-display-sm);
}

.text-lg {
  font-size: 1.125rem;
  line-height: 1.75rem;
}

.text-xl {
  font-size: 1.25rem;
  line-height: 1.75rem;
}

.font-medium {
  font-weight: 500;
}

.font-normal {
  font-weight: 400;
}

.font-semibold {
  font-weight: 600;
}

.uppercase {
  text-transform: uppercase;
}

.italic {
  font-style: italic;
}

.not-italic {
  font-style: normal;
}

.tabular-nums {
  --tw-numeric-spacing: tabular-nums;
  font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction);
}

.leading-\[1\.05\] {
  line-height: 1.05;
}

.leading-\[1\.2\] {
  line-height: 1.2;
}

.leading-\[1\.8\] {
  line-height: 1.8;
}

.leading-none {
  line-height: 1;
}

.leading-relaxed {
  line-height: 1.625;
}

.leading-tight {
  line-height: 1.25;
}

.tracking-tight {
  letter-spacing: -0.025em;
}

.tracking-wide {
  letter-spacing: 0.025em;
}

.tracking-wider {
  letter-spacing: 0.05em;
}

.tracking-widest {
  letter-spacing: 0.1em;
}

.text-background {
  color: hsl(var(--background));
}

.text-background\/70 {
  color: hsl(var(--background) / 0.7);
}

.text-foreground {
  color: hsl(var(--foreground));
}

.text-foreground\/70 {
  color: hsl(var(--foreground) / 0.7);
}

.text-foreground\/80 {
  color: hsl(var(--foreground) / 0.8);
}

.text-foreground\/90 {
  color: hsl(var(--foreground) / 0.9);
}

.text-muted-foreground {
  color: hsl(var(--muted-foreground));
}

.text-muted-foreground\/70 {
  color: hsl(var(--muted-foreground) / 0.7);
}

.text-white {
  --tw-text-opacity: 1;
  color: rgb(255 255 255 / var(--tw-text-opacity, 1));
}

.text-white\/40 {
  color: rgb(255 255 255 / 0.4);
}

.text-white\/50 {
  color: rgb(255 255 255 / 0.5);
}

.text-white\/60 {
  color: rgb(255 255 255 / 0.6);
}

.text-white\/70 {
  color: rgb(255 255 255 / 0.7);
}

.text-white\/80 {
  color: rgb(255 255 255 / 0.8);
}

.\!underline {
  text-decoration-line: underline !important;
}

.underline {
  text-decoration-line: underline;
}

.underline-offset-4 {
  text-underline-offset: 4px;
}

.opacity-0 {
  opacity: 0;
}

.opacity-20 {
  opacity: 0.2;
}

.opacity-40 {
  opacity: 0.4;
}

.opacity-50 {
  opacity: 0.5;
}

.opacity-60 {
  opacity: 0.6;
}

.opacity-70 {
  opacity: 0.7;
}

.shadow {
  --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
  --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
  box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}

.shadow-2xl {
  --tw-shadow: var(--shadow-2xl);
  --tw-shadow-colored: var(--shadow-2xl);
  box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}

.shadow-lg {
  --tw-shadow: var(--shadow-lg);
  --tw-shadow-colored: var(--shadow-lg);
  box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}

.outline {
  outline-style: solid;
}

.ring {
  --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
  --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);
  box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
}

.filter {
  filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
}

.backdrop-blur-sm {
  --tw-backdrop-blur: blur(4px);
  -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
  backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
}

.backdrop-blur-xl {
  --tw-backdrop-blur: blur(24px);
  -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
  backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
}

.transition {
  transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter;
  transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;
  transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter;
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
  transition-duration: 150ms;
}

.transition-\[left\] {
  transition-property: left;
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
  transition-duration: 150ms;
}

.transition-all {
  transition-property: all;
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
  transition-duration: 150ms;
}

.transition-colors {
  transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
  transition-duration: 150ms;
}

.transition-opacity {
  transition-property: opacity;
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
  transition-duration: 150ms;
}

.transition-transform {
  transition-property: transform;
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
  transition-duration: 150ms;
}

.duration-150 {
  transition-duration: 150ms;
}

.duration-300 {
  transition-duration: 300ms;
}

.duration-500 {
  transition-duration: 500ms;
}

.ease-out {
  transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
}

.will-change-transform {
  will-change: transform;
}

@keyframes enter {
  from {
    opacity: var(--tw-enter-opacity, 1);
    transform: translate3d(var(--tw-enter-translate-x, 0), var(--tw-enter-translate-y, 0), 0) scale3d(var(--tw-enter-scale, 1), var(--tw-enter-scale, 1), var(--tw-enter-scale, 1)) rotate(var(--tw-enter-rotate, 0));
  }
}

@keyframes exit {
  to {
    opacity: var(--tw-exit-opacity, 1);
    transform: translate3d(var(--tw-exit-translate-x, 0), var(--tw-exit-translate-y, 0), 0) scale3d(var(--tw-exit-scale, 1), var(--tw-exit-scale, 1), var(--tw-exit-scale, 1)) rotate(var(--tw-exit-rotate, 0));
  }
}

.fade-in {
  --tw-enter-opacity: 0;
}

.duration-150 {
  animation-duration: 150ms;
}

.duration-300 {
  animation-duration: 300ms;
}

.duration-500 {
  animation-duration: 500ms;
}

.ease-out {
  animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
}

.running {
  animation-play-state: running;
}

.paused {
  animation-play-state: paused;
}

.text-display-xl {
  font-family: var(--font-display);
  font-size: var(--text-display-xl);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.02em;
}

.text-display-lg {
  font-family: var(--font-display);
  font-size: var(--text-display-lg);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.02em;
}

.text-display-md {
  font-family: var(--font-display);
  font-size: var(--text-display-md);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.02em;
}

.text-display-sm {
  font-family: var(--font-display);
  font-size: var(--text-display-sm);
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: -0.01em;
}

.text-body-lg {
  font-size: var(--text-body-lg);
  line-height: 1.7;
}

.text-table {
  font-size: var(--text-table);
  line-height: 1.6;
}

.text-body-sm {
  font-size: var(--text-body-sm);
  line-height: 1.6;
}

.space-section {
  padding-top: var(--space-section);
  padding-bottom: var(--space-section);
}

.space-block {
  padding-top: var(--space-block);
  padding-bottom: var(--space-block);
}

.hero-envelope {
  height: var(--hero-h);
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

.hero-text-block {
  flex: 0 0 auto;
  max-height: calc(var(--hero-h) - var(--hero-image-min-h) - 1.5rem);
  overflow-y: auto;
  scrollbar-width: thin;
  -webkit-mask-image: linear-gradient(to bottom, hsl(0 0% 0%) calc(100% - 0.75rem), transparent);
  mask-image: linear-gradient(to bottom, hsl(0 0% 0%) calc(100% - 0.75rem), transparent);
}

.hero-text-block.is-not-overflowing {
  -webkit-mask-image: none;
  mask-image: none;
}

.hero-image-cell {
  flex: 1 1 0;
  min-height: var(--hero-image-min-h);
  overflow: hidden;
  border-radius: 0.75rem;
}

.\[hyphens\:none\] {
  -webkit-hyphens: none;
          hyphens: none;
}

.\[overflow-wrap\:normal\] {
  overflow-wrap: normal;
}

.\[word-break\:normal\] {
  word-break: normal;
}

/* Fonts: Clash Display + Satoshi from Fontshare */

/* Definition of the design system. All colors, gradients, fonts, etc should be defined here.
All colors MUST be HSL.
*/

:root {
  --ease-standard: cubic-bezier(0.25, 0.46, 0.45, 0.94);
  --ease-emphatic: cubic-bezier(0.16, 1, 0.3, 1);
  --dur-fast: 0.2s;
  --dur-quick: 0.3s;
  --dur-page: 0.4s;
  --dur-base: 0.5s;
  --dur-reveal: 0.6s;
  --dur-cross: 0.8s;
  --dur-kenburns: 8s;
  --dur-spring: 362ms;
  /* --ease-spring generated by scripts/lib/spring.mjs (springLinearEasing({ stiffness: 400, damping: 30, mass: 1 })),
     re-expressing the hero tab underline spring in src/components/HeroCarousel.tsx (layoutId="carousel-underline",
     transition={{ type: "spring", stiffness: 400, damping: 30 }}). A cubic-bezier cannot express the overshoot an
     underdamped spring produces, so the curve is sampled into linear() stops instead. */
  --ease-spring: linear(0, 0.01499, 0.05467, 0.11202, 0.18119, 0.25739, 0.33675, 0.41624, 0.49355, 0.56699, 0.63537, 0.69793, 0.75426, 0.80423, 0.84792, 0.88558, 0.91755, 0.94428, 0.96624, 0.98394, 0.99789, 1.00858, 1.01648, 1.02202, 1.02562, 1.02762, 1.02836, 1.0281, 1.0271, 1.02556, 1.02366, 1.02153, 1.01928, 1.01702, 1.01481, 1.0127, 1.01073, 1.00892, 1.00729, 1.00583, 1);
}

@keyframes progress {
  from {
    width: 0%;
  }

  to {
    width: 100%;
  }
}

@keyframes terminal-cursor-blink {
  0%, 49% {
    opacity: 1;
  }

  50%, 100% {
    opacity: 0.2;
  }
}

@media (prefers-reduced-motion: no-preference) {
  .terminal-cursor {
    animation: terminal-cursor-blink 1.1s steps(1, end) infinite;
  }
}

/* ----------------------------------------------------------- */

/* Scroll-reveal / stagger / word-reveal motion                */

/* Re-expresses src/components/ScrollReveal.tsx,                */

/* src/components/StaggerContainer.tsx and                      */

/* src/components/ScrollRevealText.tsx as CSS state toggled by  */

/* the IntersectionObserver in static/js/site.js (Task 2.2).    */

/* ----------------------------------------------------------- */

/* ScrollReveal.tsx (direction="up", the component default): initial
   { opacity: 0, y: 40 }, animate { opacity: 1, y: 0 }, transition
   { duration: 0.6, ease: [0.25, 0.46, 0.45, 0.94] } (ScrollReveal.tsx:18,31,58-61). */

.scroll-reveal {
  opacity: 0;
  transform: translateY(40px);
  transition: opacity var(--dur-reveal) var(--ease-standard),
    transform var(--dur-reveal) var(--ease-standard);
}

/* ScrollReveal.tsx direction variants — getInitialPosition (ScrollReveal.tsx:30-35):
   "down" flips y to -40, "left"/"right" swap the animated axis to x (±40). */

.scroll-reveal--down {
  transform: translateY(-40px);
}

.scroll-reveal--left {
  transform: translateX(40px);
}

.scroll-reveal--right {
  transform: translateX(-40px);
}

.scroll-reveal.is-revealed {
  opacity: 1;
  transform: none;
}

/* StaggerContainer.tsx containerVariants: hidden { opacity: 0 }, visible
   { opacity: 1, transition: { staggerChildren, delayChildren } }
   (StaggerContainer.tsx:4-11), applied to the motion.div wrapping the group
   itself, separately from each child's own itemVariants below. Framer leaves
   this transition unspecified, so it falls back to the library's own default
   tween for a non-transform value — { ease: [0.25, 0.1, 0.35, 1], duration: 0.3 }
   (motion-dom's getDefaultTransition — confirmed in
   node_modules/motion-dom/dist/es/animation/utils/default-transitions.mjs in
   the React repo). --dur-quick is the only token in tailwind.css that equals
   that 0.3s default; no token models the default ease curve, so --ease-standard
   (already used throughout this section) stands in for it — the two curves
   are both shallow ease-outs and the resulting difference is not the
   contract this task is pinning down. Because rendered opacity is
   multiplicative down the DOM tree, this container-level fade plus the
   child-level fade below together produce React's visibly softer, two-stage
   group entrance; dropping it leaves the container always fully opaque. */

[data-stagger] {
  opacity: 0;
  transition: opacity var(--dur-quick) var(--ease-standard);
}

[data-stagger].is-revealed {
  opacity: 1;
}

/* StaggerContainer.tsx itemVariants: hidden { opacity: 0, y: 20 }, visible
   { opacity: 1, y: 0, transition: { duration: 0.5, ease: [0.25, 0.46, 0.45, 0.94] } }
   (StaggerContainer.tsx:22-29). The stagger/delay itself (staggerChildren: 0.1,
   delayChildren: 0.1, StaggerContainer.tsx:15-16,49) is applied per-child as an
   inline transition-delay by static/js/site.js — CSS cannot express "nth child" timing
   without knowing child count ahead of time. */

.stagger-item {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity var(--dur-base) var(--ease-standard),
    transform var(--dur-base) var(--ease-standard);
}

.stagger-item.is-revealed {
  opacity: 1;
  transform: none;
}

/* ScrollRevealText.tsx per-word span: initial { opacity: 0, y: 20 }, animate
   { opacity: 1, y: 0 }, transition { duration: 0.5, ease: [0.25, 0.46, 0.45, 0.94] },
   className "inline-block mr-[0.3em]" (ScrollRevealText.tsx:24-35). Per-word delay
   (i * staggerDelay, ScrollRevealText.tsx:32) is applied as an inline transition-delay
   by static/js/site.js, same reason as .stagger-item above. */

.word-reveal span {
  display: inline-block;
  margin-right: 0.3em;
  opacity: 0;
  transform: translateY(20px);
  transition: opacity var(--dur-base) var(--ease-standard),
    transform var(--dur-base) var(--ease-standard);
}

.word-reveal span.is-revealed {
  opacity: 1;
  transform: none;
}

/* Reduced motion is a bail-out, not a shortening: ScrollReveal.tsx:24-26,
   StaggerContainer.tsx:39, ScrollRevealText.tsx:17-19 all return the plain,
   unanimated element when useReducedMotion() is true — nothing hidden, nothing
   transformed, nothing transitions. A shortened duration here would still be a
   defect even though this rule alone cannot undo a state JS never sets; see the
   REDUCED branch in static/js/site.js's revealOnce(), which reveals every node
   synchronously instead of relying on the observer. [data-stagger] MUST be
   listed here alongside its .stagger-item children: it carries its own
   `opacity: 0` base state above, so a reduced-motion user whose JS never runs
   (or runs before this class exists in the DOM) would otherwise see a
   permanently invisible group — a worse defect than the two-stage entrance
   this rule exists to bypass. */

@media (prefers-reduced-motion: reduce) {
  .scroll-reveal, [data-stagger], .stagger-item, .word-reveal span {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
}

/* ----------------------------------------------------------- */

/* Case-study component motion                                 */

/* Re-expresses src/components/work/CaseImage.tsx,              */

/* CaseMetrics.tsx, CaseStatement.tsx and CaseTimeline.tsx      */

/* as CSS state toggled by static/js/site.js (Task 4.1).        */

/* ----------------------------------------------------------- */

/* CaseImage.tsx:24-34 full-bleed motion.img initial
   { opacity: 0, scale: 1.02 } -> { opacity: 1, scale: 1 },
   transition { duration: 0.8, ease: [0.16, 1, 0.3, 1] }. */

.case-image-media {
  opacity: 0;
  transition: opacity var(--dur-cross) var(--ease-emphatic),
    transform var(--dur-cross) var(--ease-emphatic);
}

.case-image-media--full {
  transform: scale(1.02);
}

/* CaseImage.tsx:52-61 offset motion.img uses 0.7s, which has no
   project duration token, so the literal is preserved. */

.case-image-media--offset-right,
.case-image-media--offset-left {
  transition-duration: 0.7s;
}

.case-image-media--offset-right {
  transform: translateX(30px);
}

.case-image-media--offset-left {
  transform: translateX(-30px);
}

.case-image-media.is-revealed {
  opacity: 1;
  transform: none;
}

/* CaseMetrics.tsx:107-112 wrapper fade, transition duration 0.6s
   with framer-motion's default ease. */

.case-metrics {
  opacity: 0;
  transition: opacity var(--dur-reveal) var(--ease-standard);
}

.case-metrics.is-revealed {
  opacity: 1;
}

/* CaseStatement.tsx:18 motion.p initial { opacity: 0, y: 20 }
   -> { opacity: 1, y: 0 }, duration 0.8s, emphatic ease. */

.case-statement-text {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity var(--dur-cross) var(--ease-emphatic),
    transform var(--dur-cross) var(--ease-emphatic);
}

.case-statement-text.is-revealed {
  opacity: 1;
  transform: none;
}

/* CaseTimeline.tsx:24-34 per-entry motion.div initial
   { opacity: 0, y: 16 } -> { opacity: 1, y: 0 }, duration 0.5s,
   delay i * 0.1s supplied by static/js/site.js. */

.case-timeline-entry {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity var(--dur-base) var(--ease-emphatic),
    transform var(--dur-base) var(--ease-emphatic);
}

.case-timeline-entry.is-revealed {
  opacity: 1;
  transform: none;
}

/* CaseImage.tsx:27-30,55-58; CaseMetrics.tsx:20-24,97-104;
   CaseStatement.tsx:15-18; CaseTimeline.tsx:26-33 -- reduced motion
   renders the final static element with no transform and no transition. */

@media (prefers-reduced-motion: reduce) {
  .case-image-media, .case-metrics, .case-statement-text, .case-timeline-entry {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
}

/* ----------------------------------------------------------- */

/* Page transitions — cross-document View Transitions API       */

/* Re-expresses src/components/PageTransition.tsx as a          */

/* declarative, browser-driven transition: `navigation: auto`   */

/* opts every same-origin document navigation into the API with */

/* zero JavaScript. Engines without cross-document View          */

/* Transitions support ignore the at-rule and navigate           */

/* immediately, which is the correct degradation — not a        */

/* fallback to author.                                           */

/* ----------------------------------------------------------- */

@view-transition {
  navigation: auto;
}

/* PageTransition.tsx exit: { opacity: 1, y: 0 } -> { opacity: 0, y: -20 }
   (PageTransition.tsx:16). The outgoing document is ::view-transition-old(root). */

@keyframes vt-exit {
  to {
    opacity: 0;
    transform: translateY(-20px);
  }
}

/* PageTransition.tsx enter: { opacity: 0, y: 20 } -> { opacity: 1, y: 0 }
   (PageTransition.tsx:14-15). The incoming document is ::view-transition-new(root). */

@keyframes vt-enter {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
}

/* transition: { duration: 0.4, ease: [0.25, 0.46, 0.45, 0.94] } (PageTransition.tsx:17-20)
   -> --dur-page (0.4s) and --ease-standard, already used throughout this file. */

::view-transition-old(root) {
  animation: vt-exit var(--dur-page) var(--ease-standard) both;
}

::view-transition-new(root) {
  animation: vt-enter var(--dur-page) var(--ease-standard) both;
}

/* PageTransition.tsx: useReducedMotion() true renders the plain, unanimated
   child with no motion.div wrapper at all (PageTransition.tsx:9-10) — a
   bail-out, not a shortened transition. animation: none, not a shorter one. */

@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root), ::view-transition-new(root) {
    animation: none;
  }
}

/* ----------------------------------------------------------- */

/* FloatingNav popovers — enter animation                       */

/* Task 2.5 fix round (controller ruling P2-I): re-expresses     */

/* src/components/FloatingNav.tsx's framer-motion ENTER          */

/* transitions on the pill, both popovers and the backdrop as    */

/* plain CSS `animation`s, bound directly to                     */

/* templates/components/floating_nav.html's                     */

/* .floating-nav-pill/.floating-nav-popover/.floating-nav-backdrop */

/* classes (not to a JS-added/removed class): a browser restarts */

/* a CSS animation whenever an element's `display` goes from     */

/* `none` to rendered, and static/js/site.js's openPopover()/     */

/* closePopover() already do exactly that by toggling the        */

/* `hidden` attribute (Task 2.5) — so the enter transition        */

/* replays on every open with no JS timing changes needed. The    */

/* EXIT fade (AnimatePresence's unmount transition) is NOT        */

/* ported — see floating_nav.html's own provenance comment for   */

/* why (no existing precedent anywhere in this codebase for a     */

/* JS-timed CSS exit animation).                                  */

/* ----------------------------------------------------------- */

/* FloatingNav.tsx:111-112,256 — enterPill { y: 100, opacity: 0 } ->
   restPill { y: 0, opacity: 1 }, transition { delay: 0.5, duration: 0.5,
   ease: [0.25, 0.46, 0.45, 0.94] } — the ease is --ease-standard verbatim,
   the duration is --dur-base verbatim. This plays on every page load (the
   pill is not gated behind any user interaction), matching React's own
   mount-time entrance. */

@keyframes floating-nav-pill-enter {
  from {
    opacity: 0;
    transform: translateY(100px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.floating-nav-pill {
  animation: floating-nav-pill-enter var(--dur-base) var(--ease-standard) 0.5s both;
}

/* FloatingNav.tsx:113-114,175,217 — enterPop { opacity: 0, y: 10, scale:
   0.95 } -> restPop { opacity: 1, y: 0, scale: 1 }, transition { duration:
   0.2 } (no explicit `ease` key — framer-motion's own tween default
   applies; --ease-standard stands in for it, the same precedent
   [data-stagger]'s own comment above already establishes for an
   unspecified framer-motion default). Duration 0.2 is --dur-fast
   verbatim. */

@keyframes floating-nav-popover-enter {
  from {
    opacity: 0;
    transform: translateY(10px) scale(0.95);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.floating-nav-popover {
  animation: floating-nav-popover-enter var(--dur-fast) var(--ease-standard) both;
}

/* FloatingNav.tsx:143-157 — the invisible, aria-hidden backdrop's own
   opacity 0 -> 1 fade. No `transition` prop is given (only
   initial/animate/exit), the same "unspecified framer-motion default"
   case [data-stagger]'s own comment above resolves to --dur-quick (0.3s)
   + --ease-standard; reused verbatim here for the same reason. The
   backdrop carries no background colour of its own in React either (no
   `bg-*` class on its motion.div), so this fade currently has no visible
   effect in production there or here — ported for source parity with
   FloatingNav.tsx, not because it is visible today. */

@keyframes floating-nav-backdrop-enter {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

.floating-nav-backdrop {
  animation: floating-nav-backdrop-enter var(--dur-quick) var(--ease-standard) both;
}

/* FloatingNav.tsx:111-114 — reduceMotion collapses every variant to
   opacity-only with duration/delay forced to 0 (:256 `delay: reduceMotion
   ? 0 : 0.5`, `duration: reduceMotion ? 0 : 0.5`; :175,217 `duration:
   reduceMotion ? 0 : 0.2`) — a bail-out, not a shortening, matching this
   file's own .scroll-reveal/[data-stagger]/.stagger-item/.word-reveal
   precedent immediately above: disable the animation entirely (rather
   than merely speeding it up) so the pill/popovers/backdrop render at
   their natural, fully visible, untransformed state with no transition
   at all. Nothing else needs overriding here (unlike that precedent's
   `!important` overrides) because these three classes carry no static
   opacity/transform of their own outside the `animation` shorthand
   above — `animation: none` alone is enough to fall back to the
   element's normal, fully-rendered state. */

@media (prefers-reduced-motion: reduce) {
  .floating-nav-pill, .floating-nav-popover, .floating-nav-backdrop {
    animation: none;
  }
}

/* ----------------------------------------------------------- */

/* ProjectDetail.tsx / CaseSidebar.tsx case-study body + sidebar */

/* Task 4.3 — templates/work/page.html, templates/components/   */

/* case_sidebar.html                                             */

/* ----------------------------------------------------------- */

/* RustyShieldCase.tsx:12-19,31-34 (and every other custom case body):
   ScrollReveal-wrapped <section> headings/paragraphs share this fixed
   typography regardless of which project's case-body markdown supplies
   them, so it is expressed once here rather than per-heading in markdown.
   `.case-body h2` = text-display-md mt-8 mb-10 text-foreground;
   `.case-body p` = text-body-lg leading-[1.8] max-w-2xl text-muted-foreground;
   a *second* paragraph in the same section gets React's literal `mt-6`
   (RustyShieldCase.tsx:33) — markdown has no per-paragraph className, so the
   adjacent-sibling selector below re-expresses the same rendered spacing;
   `strong` = text-foreground (RustyShieldCase.tsx:29); `code` is
   deliberately left unstyled, matching React's bare <code> (RustyShieldCase.tsx:11). */

.case-body h2 {
  margin-top: 2rem;
  margin-bottom: 2.5rem;
  color: hsl(var(--foreground));
  font-family: var(--font-display);
  font-size: var(--text-display-md);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.02em;
}

.case-body p {
  max-width: 42rem;
  color: hsl(var(--muted-foreground));
  font-size: var(--text-body-lg);
  /* leading-[1.8] (RustyShieldCase.tsx:17): Tailwind's @apply silently drops
     bracketed arbitrary-value utilities rather than erroring, so this is
     set directly rather than through @apply's utility list above. */
  line-height: 1.8;
}

.case-body p + p {
  margin-top: 1.5rem;
}

.case-body strong {
  color: hsl(var(--foreground));
}

/* CaseSidebar.tsx:60-64 — motion.aside initial {opacity:0, x:-20}, animate
   {opacity:1, x:0}, transition {delay:0.3, duration:0.5}. This is a one-shot
   entrance on mount, not an IntersectionObserver reveal (the sidebar is
   already in the viewport at load on the breakpoints it renders at), so it
   is expressed as a plain CSS animation rather than the .scroll-reveal
   observer-toggled class. --dur-quick (0.3s) stands in for the delay and
   --dur-base (0.5s) for the duration; --ease-standard stands in for
   Framer's unspecified-transition default tween, same substitution as
   [data-stagger] above. */

@keyframes case-sidebar-enter {
  from {
    opacity: 0;
    transform: translateX(-20px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

/* Task 5.2: BlogSidebar.tsx:76-80's sidebar variant is the *same* Framer
   transition (opacity 0->1, x -20->0, delay 0.3s, duration 0.5s), so it
   joins this rule rather than declaring a second identical animation --
   including its reduced-motion bail-out below. */

@media (prefers-reduced-motion: no-preference) {
  [data-case-sidebar],
  [data-blog-sidebar] {
    animation: case-sidebar-enter var(--dur-base) var(--ease-standard) var(--dur-quick) both;
  }
}

/* Reduced motion is a bail-out, not a shortening (CaseSidebar.tsx carries no
   explicit reduced-motion branch of its own, but the site-wide contract in
   constraints.md applies uniformly): scoping the animation to the
   no-preference query above means a reduced-motion visitor's <aside> never
   receives the animation shorthand at all, so it never carries the opacity:0
   / translateX(-20px) "from" state either — it renders fully visible and
   untransformed from first paint, with no override needed here. */

@media (prefers-reduced-motion: reduce) {
  [data-case-sidebar] {
    animation: none;
  }
}

/* ----------------------------------------------------------- */

/* Print stylesheet for long-form technical posts (article view) */

/* ----------------------------------------------------------- */

/* ------------------------------------------------------------------ */

/* Article body typography, code-block palette and lightbox            */

/* Task 5.1 — templates/components/{abstract,callout,footnote,          */

/* footnote_list,blog_image,code_block,d3_chart,data_table,dense_table, */

/* math,terminal_output}.html and the article route template's          */

/* `.article-body` content wrapper                                      */

/* ------------------------------------------------------------------ */

/* React styles article prose per-element in JSX (the P/UL/OL/blockquote
   constants at SupplyChainDependencyContent.tsx:7-11 and the heading ranks
   in HeadingAnchor.tsx / SectionHeading.tsx). Markdown has no per-element
   className, so the same rendered result is expressed once here, scoped to
   the `.article-body` wrapper the article route template puts around
   `page.content`. */

/* SectionHeading.tsx:14-21 — the H2 rank is
   `text-[length:var(--text-display-sm)]` plus ARTICLE_HEADING_FACE
   (HeadingAnchor.tsx:33-34) plus `scroll-mt-24`, inside a `mt-16 mb-6`
   wrapper whose first child is `<hr class="w-16 border-t
   border-muted-foreground/20 mb-8 mx-auto">`. Markdown emits a bare <h2>,
   so the wrapper's spacing lands on the heading itself and the divider is
   re-expressed as an ::before rule with the same 4rem width, 2rem gap and
   token colour.

   Sizes are arbitrary lengths, never Tailwind's named steps, for the reason
   HeadingAnchor.tsx:43-49 gives in the reference's own words: the named
   steps also set a line-height, which would override the face's
   `leading-[1.2]` — at the `md` breakpoint through the cascade, and
   unprefixed through tailwind-merge, which treats font-size as conflicting
   with leading. */

.article-body h2 {
  margin-top: 4rem;
  margin-bottom: 1.5rem;
  scroll-margin-top: 6rem;
  font-family: Clash Display, sans-serif;
  font-weight: 500;
  color: hsl(var(--foreground));
  font-size: var(--text-display-sm);
  line-height: 1.2;
  letter-spacing: -0.01em;
}

.article-body h2::before {
  content: "";
  display: block;
  width: 4rem;
  margin: 0 auto 2rem;
  border-top: 1px solid hsl(var(--muted-foreground) / 0.2);
}

/* HeadingAnchor.tsx:57 — H3_RANK. */

.article-body h3 {
  margin-top: 3rem;
  margin-bottom: 1.5rem;
  scroll-margin-top: 6rem;
  font-family: Clash Display, sans-serif;
  font-weight: 500;
  color: hsl(var(--foreground));
  font-size: 1.25rem;
  line-height: 1.2;
  letter-spacing: -0.01em;
}

/* HeadingAnchor.tsx:59 — H4_RANK. */

.article-body h4 {
  margin-top: 2.5rem;
  margin-bottom: 0.75rem;
  scroll-margin-top: 6rem;
  font-family: Clash Display, sans-serif;
  font-weight: 500;
  color: hsl(var(--foreground));
  font-size: 1.125rem;
  line-height: 1.2;
  letter-spacing: -0.01em;
}

@media (min-width: 768px) {
  .article-body h3 {
    font-size: 1.5rem;
  }

  .article-body h4 {
    font-size: 1.25rem;
  }
}

/* SupplyChainDependencyContent.tsx:7-11 — P, UL and OL. `leading-[1.8]` is
   set directly rather than through @apply for the same reason .case-body p
   above does it: @apply silently drops bracketed arbitrary values.

   The `:not(:where(section[data-toc-skip] …))` guards keep these prose rules
   out of the footnote list. React renders <FootnoteList /> as a *sibling* of
   the prose (BlogPost.tsx:196), so no article-body rule reaches it there;
   here the list is authored at the end of the Markdown body and therefore
   lands inside .article-body, where these rules would outrank the component's
   own utilities (Footnote.tsx:63-99: `text-body-sm` on the section,
   `text-[11px] mb-4` on the label, `space-y-3 list-decimal pl-5` on the <ol>).
   `:where()` keeps the guard at zero specificity, so ordinary prose still
   matches at the original (0,1,1) and nothing else shifts. `data-toc-skip`
   marks page furniture and appears nowhere else in the templates. */

.article-body p:not(:where(section[data-toc-skip] p)) {
  margin-bottom: 2rem;
  color: hsl(var(--muted-foreground));
  font-size: var(--text-body-lg);
  line-height: 1.8;
}

.article-body ul:not(:where(section[data-toc-skip] *)),
.article-body ol:not(:where(section[data-toc-skip] *)) {
  margin-bottom: 2rem;
}

.article-body ul:not(:where(section[data-toc-skip] *)) > :not([hidden]) ~ :not([hidden]),
.article-body ol:not(:where(section[data-toc-skip] *)) > :not([hidden]) ~ :not([hidden]) {
  --tw-space-y-reverse: 0;
  margin-top: calc(0.75rem * calc(1 - var(--tw-space-y-reverse)));
  margin-bottom: calc(0.75rem * var(--tw-space-y-reverse));
}

.article-body ul:not(:where(section[data-toc-skip] *)),
.article-body ol:not(:where(section[data-toc-skip] *)) {
  padding-left: 1.5rem;
  color: hsl(var(--muted-foreground));
  font-size: var(--text-body-lg);
  line-height: 1.8;
}

.article-body ul {
  list-style-type: disc;
}

.article-body ol {
  list-style-type: decimal;
}

/* SupplyChainDependencyContent.tsx:29-38 — the pull quote and its <cite>.
   The <cite> is the one place ruling P5-K permits raw HTML in an article
   body, because Markdown has no citation element. */

.article-body blockquote {
  margin-top: 3rem;
  margin-bottom: 3rem;
  border-left-width: 2px;
  border-color: hsl(var(--foreground));
  padding-left: 2rem;
  font-style: italic;
  color: hsl(var(--foreground));
  font-size: var(--text-body-lg);
  line-height: 1.7;
}

.article-body blockquote cite {
  margin-top: 1rem;
  display: block;
  font-style: normal;
  color: hsl(var(--muted-foreground));
  font-size: var(--text-body-sm);
  line-height: 1.6;
}

/* strong inherits its colour from the surrounding prose, matching React's
   bare <strong> in the same source. */

/* Nested prose inside the article's own components keeps that component's
   own type, so the .article-body paragraph rule must not reach into a
   callout, a table cell or a figure caption.

   `blockquote p` is in the list for a structural reason rather than a
   component one: React puts the pull quote's text directly inside
   <blockquote> (SupplyChainDependencyContent.tsx:29-38), while Markdown
   always wraps a blockquote's content in a <p>. Without this the quote would
   render at the paragraph rule's muted colour with a bottom margin instead
   of the blockquote's own `italic text-body-lg text-foreground`. */

.article-body blockquote p,
.article-body aside[role="note"] p,
.article-body figure p,
.article-body figcaption,
.article-body td p,
.article-body th p {
  margin-bottom: 0px;
  font-size: inherit;
  line-height: inherit;
  color: inherit;
}

/* ------------------------------------------------------------------ */

/* code_block syntax palette (ruling P5-F)                             */

/* ------------------------------------------------------------------ */

/* React highlights with prism-react-renderer and the inline `riderNightTheme`
   object at CodeBlock.tsx:13-33. Zola highlights at build time with its own
   engine (giallo), which — verified empirically on 0.23.3 — emits
   *colour-slot* classes, not token classes: `.z-1` … `.z-12` are the
   distinct colours of the configured theme in sorted order, plus `.z-b`,
   `.z-i`, `.z-u`, `.z-s` for weight/style. The slot-to-token association is
   therefore fixed by the theme (`one-dark-pro`, config.toml) and is read off
   the stylesheet zola itself generates.

   Mapping, slot → the scopes one-dark-pro assigns that colour → the Rider
   Night colour React paints the same role:

     base   #ABB2BF  plain text, operators, punctuation, parameters  → #bcbec4  (CodeBlock.tsx:15, :27-28)
     bg     #282C34  code surface                                     → #1e1f22  (:16)
     .z-1   #56B6C2  support.function, keyword.operator.*, regexp     → #56a8f5  (:25 function/method)
     .z-2   #5C6370  markup.link, markup.quote                        → #868a91  (:20 comment, the dim slot)
     .z-3   #61AFEF  entity.name.function, meta.function-call         → #56a8f5  (:25)
     .z-4   #7F848E  comment, punctuation.definition.comment          → #868a91  (:20)
     .z-5   #98C379  string, string.quoted, markup.inline.raw         → #6aab73  (:21)
     .z-6   #BE5046  punctuation.section.embedded                     → #cf8e6d  (:22 keyword)
     .z-7   #C678DD  keyword, keyword.control, storage                → #cf8e6d  (:22)
     .z-8   #D19A66  constant, constant.numeric, attribute-name       → #2aacb8  (:26 number/boolean)
     .z-9   #E06C75  variable, entity.name.tag, punctuation           → #bcbec4  (:28 property/constant/variable)
     .z-10  #E5C07B  entity.name.class, entity.name.type, storage.type → #c77dbb  (:24 class-name/builtin)
     .z-11  #F44747  invalid.illegal, error tokens                    → #e06c75  (TerminalOutput.tsx:33 ACCENT_ERR)
     .z-12  #FFFFFF  invalid.*                                        → #e06c75  (same)

   Recorded stack difference: prism and giallo do not agree on which token a
   lexeme belongs to, so per-token parity is not claimable and is not
   claimed. Two known disagreements the slot scheme cannot close, because the
   slot is shared with a role React paints differently:
     - `entity.other.attribute-name` shares slot 8 with numerics, so an HTML
       attribute name renders in React's number colour rather than its
       attr-name blue (#56a8f5, CodeBlock.tsx:29);
     - `meta.function.decorator.python` shares slot 1 with support functions,
       so a Python decorator renders blue rather than React's #bbb529 (:31).
   Both are colour-only, inside a code block, on a language the article does
   not use.

   Scoped to `[data-code-block]` rather than emitted globally, because in
   React the theme is a prop of CodeBlock, not a document-level stylesheet;
   `templates/components/terminal_output.html` and `dense_table.html` carry
   their own inline palette exactly as their React counterparts do. */

[data-code-block] .z-code,
[data-code-block] pre.giallo {
  color: #bcbec4;
  background-color: #1e1f22;
}

[data-code-block] .z-hl {
  background-color: #2b2d30;
}

[data-code-block] .giallo-ln {
  color: #7a7e85;
}

[data-code-block] .z-1,
[data-code-block] .z-3 {
  color: #56a8f5;
}

[data-code-block] .z-2,
[data-code-block] .z-4 {
  color: #868a91;
}

[data-code-block] .z-5 {
  color: #6aab73;
}

[data-code-block] .z-6,
[data-code-block] .z-7 {
  color: #cf8e6d;
}

[data-code-block] .z-8 {
  color: #2aacb8;
}

[data-code-block] .z-9 {
  color: #bcbec4;
}

[data-code-block] .z-10 {
  color: #c77dbb;
}

[data-code-block] .z-11,
[data-code-block] .z-12 {
  color: #e06c75;
}

[data-code-block] .z-b {
  font-weight: bold;
}

[data-code-block] .z-i {
  font-style: italic;
}

[data-code-block] .z-u {
  text-decoration: underline;
}

[data-code-block] .z-s {
  text-decoration: line-through;
}

[data-code-block] .z-us {
  text-decoration: underline line-through;
}

/* ------------------------------------------------------------------ */

/* Lightbox dialog (Lightbox.tsx:23-32)                                */

/* ------------------------------------------------------------------ */

/* React's Lightbox is a Radix <Dialog>; its DialogContent carries
   `max-w-[95vw] w-auto p-2 sm:p-4 bg-background border-border` and portals
   to the document root. The static port uses one native <dialog
   data-lightbox> per document, opened by static/js/site.js from the
   `data-lightbox-trigger` buttons blog_image.html emits, so the same
   classes are expressed here against that element instead. */

dialog[data-lightbox] {
  width: auto;
  border-radius: var(--radius);
  border-width: 1px;
  border-color: hsl(var(--border));
  background-color: hsl(var(--background));
  padding: 0.5rem;
}

@media (min-width: 640px) {
  dialog[data-lightbox] {
    padding: 1rem;
  }
}

dialog[data-lightbox] {
  max-width: 95vw;
}

dialog[data-lightbox]::backdrop {
  background-color: hsl(var(--background) / 0.8);
}

dialog[data-lightbox] img {
  margin-left: auto;
  margin-right: auto;
  height: auto;
  width: auto;
  -o-object-fit: contain;
     object-fit: contain;
  max-width: 90vw;
  max-height: 80vh;
}

dialog[data-lightbox] [data-lightbox-caption-text] {
  margin-top: 0.75rem;
  text-align: center;
  color: hsl(var(--muted-foreground));
  font-size: var(--text-body-sm);
  line-height: 1.6;
}

dialog[data-lightbox] [data-lightbox-caption-text]:empty {
  display: none;
}

/* ------------------------------------------------------------------ */

/* Home variants and carousels                                        */

/* ------------------------------------------------------------------ */

/* Home.tsx / useHomeVariant.ts: the bootstrap writes this attribute in
   base.html before first paint; the inactive panel therefore never flashes. */

html[data-home-variant="minimal"] [data-home-variant-panel="studio"],
html:not([data-home-variant="minimal"]) [data-home-variant-panel="minimal"] {
  display: none;
}

/* HomeVariantSwitch.tsx:16-19. */

.home-variant-switch {
  animation: home-variant-switch-enter var(--dur-page) var(--ease-standard) 0.4s both;
}

@keyframes home-variant-switch-enter {
  from {
    opacity: 0;
    transform: translateY(-40px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* HeroCarousel.tsx:65-104 -- concurrent image crossfade, Ken Burns drift and
   the delayed copy swap. First paint is already .is-active, so no fade. */

.hero-carousel-slide {
  opacity: 0;
  transition: opacity var(--dur-cross) var(--ease-standard);
}

.hero-carousel-slide.is-active {
  opacity: 1;
}

.hero-carousel-slide.is-active .hero-carousel-ken-burns {
  animation: hero-ken-burns var(--dur-kenburns) linear both;
}

@keyframes hero-ken-burns {
  from {
    transform: translate(-1.5%, -1.5%) scale(1.05);
  }

  to {
    transform: translate(1.5%, 1.5%) scale(1.18);
  }
}

.hero-carousel-copy {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity var(--dur-base) var(--ease-standard), transform var(--dur-base) var(--ease-standard);
}

.hero-carousel-copy.is-active {
  opacity: 1;
  transform: translateY(0);
}

.hero-carousel-underline {
  left: 0;
  width: 0;
  transition: transform var(--dur-spring) var(--ease-spring), width var(--dur-spring) var(--ease-spring);
}

.project-carousel-progress {
  width: 0;
  transition: width var(--dur-quick) var(--ease-standard);
}

.project-carousel-progress.is-past {
  width: 100%;
}

.project-carousel-progress.is-active {
  animation: progress 6s linear forwards;
}

@media (prefers-reduced-motion: reduce) {
  .home-variant-switch {
    animation: none;
  }

  .hero-carousel-slide,
  .hero-carousel-copy,
  .hero-carousel-underline,
  .project-carousel-progress {
    transition: none;
  }

  .hero-carousel-slide.is-active .hero-carousel-ken-burns,
  .project-carousel-progress.is-active {
    animation: none;
    transform: none;
  }
}

@media print {
  [data-print="hidden"],
  .no-print {
    display: none !important;
  }

  body {
    background: #ffffff !important;
    color: #111111 !important;
  }

  main,
  article,
  .container {
    max-width: none !important;
    padding: 0 !important;
    margin: 0 !important;
  }

  article a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 0.85em;
    color: #555555;
    word-break: break-all;
  }

  pre {
    background: #f5f5f5 !important;
    color: #111111 !important;
    white-space: pre-wrap !important;
    border: 1px solid #dddddd;
  }

  pre code,
  pre code * {
    color: #111111 !important;
    background: transparent !important;
  }

  h1, h2, h3 {
    color: #111111 !important;
  }

  h2 {
    -moz-column-break-before: page;
         break-before: page;
  }

  figure, pre, table, aside[role="note"] {
    -moz-column-break-inside: avoid;
         break-inside: avoid;
  }

  .footnote-backref::after {
    content: " ↩";
  }

  .mermaid-surface svg {
    background: #ffffff !important;
  }

  .mermaid-surface svg text {
    fill: #111111 !important;
  }
}

.placeholder\:text-muted-foreground::-moz-placeholder {
  color: hsl(var(--muted-foreground));
}

.placeholder\:text-muted-foreground::placeholder {
  color: hsl(var(--muted-foreground));
}

.first\:pt-0:first-child {
  padding-top: 0px;
}

.last\:border-0:last-child {
  border-width: 0px;
}

.last\:border-b-0:last-child {
  border-bottom-width: 0px;
}

.last\:pb-0:last-child {
  padding-bottom: 0px;
}

.hover\:border-foreground\/20:hover {
  border-color: hsl(var(--foreground) / 0.2);
}

.hover\:border-foreground\/30:hover {
  border-color: hsl(var(--foreground) / 0.3);
}

.hover\:border-foreground\/40:hover {
  border-color: hsl(var(--foreground) / 0.4);
}

.hover\:border-muted-foreground:hover {
  border-color: hsl(var(--muted-foreground));
}

.hover\:bg-foreground:hover {
  background-color: hsl(var(--foreground));
}

.hover\:bg-muted:hover {
  background-color: hsl(var(--muted));
}

.hover\:bg-muted\/20:hover {
  background-color: hsl(var(--muted) / 0.2);
}

.hover\:bg-muted\/40:hover {
  background-color: hsl(var(--muted) / 0.4);
}

.hover\:text-background:hover {
  color: hsl(var(--background));
}

.hover\:text-foreground:hover {
  color: hsl(var(--foreground));
}

.hover\:text-muted-foreground:hover {
  color: hsl(var(--muted-foreground));
}

.hover\:text-white:hover {
  --tw-text-opacity: 1;
  color: rgb(255 255 255 / var(--tw-text-opacity, 1));
}

.hover\:text-white\/60:hover {
  color: rgb(255 255 255 / 0.6);
}

.hover\:underline:hover {
  text-decoration-line: underline;
}

.hover\:opacity-100:hover {
  opacity: 1;
}

.hover\:opacity-70:hover {
  opacity: 0.7;
}

.hover\:opacity-80:hover {
  opacity: 0.8;
}

.focus\:not-sr-only:focus {
  position: static;
  width: auto;
  height: auto;
  padding: 0;
  margin: 0;
  overflow: visible;
  clip: auto;
  white-space: normal;
}

.focus\:fixed:focus {
  position: fixed;
}

.focus\:left-3:focus {
  left: 0.75rem;
}

.focus\:top-3:focus {
  top: 0.75rem;
}

.focus\:z-\[200\]:focus {
  z-index: 200;
}

.focus\:rounded-md:focus {
  border-radius: calc(var(--radius) - 2px);
}

.focus\:bg-foreground:focus {
  background-color: hsl(var(--foreground));
}

.focus\:px-4:focus {
  padding-left: 1rem;
  padding-right: 1rem;
}

.focus\:py-2:focus {
  padding-top: 0.5rem;
  padding-bottom: 0.5rem;
}

.focus\:text-background:focus {
  color: hsl(var(--background));
}

.focus\:shadow-2xl:focus {
  --tw-shadow: var(--shadow-2xl);
  --tw-shadow-colored: var(--shadow-2xl);
  box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}

.focus\:outline-none:focus {
  outline: 2px solid transparent;
  outline-offset: 2px;
}

.focus-visible\:text-muted-foreground:focus-visible {
  color: hsl(var(--muted-foreground));
}

.focus-visible\:outline-none:focus-visible {
  outline: 2px solid transparent;
  outline-offset: 2px;
}

.focus-visible\:ring-1:focus-visible {
  --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
  --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
  box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
}

.focus-visible\:ring-2:focus-visible {
  --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
  --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
  box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
}

.focus-visible\:ring-background:focus-visible {
  --tw-ring-color: hsl(var(--background));
}

.focus-visible\:ring-foreground:focus-visible {
  --tw-ring-color: hsl(var(--foreground));
}

.focus-visible\:ring-foreground\/40:focus-visible {
  --tw-ring-color: hsl(var(--foreground) / 0.4);
}

.focus-visible\:ring-ring:focus-visible {
  --tw-ring-color: hsl(var(--ring));
}

.focus-visible\:ring-offset-2:focus-visible {
  --tw-ring-offset-width: 2px;
}

.focus-visible\:ring-offset-background:focus-visible {
  --tw-ring-offset-color: hsl(var(--background));
}

.focus-visible\:ring-offset-foreground:focus-visible {
  --tw-ring-offset-color: hsl(var(--foreground));
}

.group[open] .group-open\:rotate-180 {
  --tw-rotate: 180deg;
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}

.group:hover .group-hover\:translate-x-0\.5 {
  --tw-translate-x: 0.125rem;
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}

.group:hover .group-hover\:translate-x-1 {
  --tw-translate-x: 0.25rem;
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}

.group:hover .group-hover\:border-foreground\/30 {
  border-color: hsl(var(--foreground) / 0.3);
}

.group:hover .group-hover\:text-foreground {
  color: hsl(var(--foreground));
}

.group:hover .group-hover\:opacity-100 {
  opacity: 1;
}

.group:hover .group-hover\:opacity-70 {
  opacity: 0.7;
}

.group:focus-visible .group-focus-visible\:border-foreground\/30 {
  border-color: hsl(var(--foreground) / 0.3);
}

.has-\[\.work-card-link\:focus-visible\]\:scale-105:has(.work-card-link:focus-visible) {
  --tw-scale-x: 1.05;
  --tw-scale-y: 1.05;
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}

.has-\[\.work-card-link\:hover\]\:scale-105:has(.work-card-link:hover) {
  --tw-scale-x: 1.05;
  --tw-scale-y: 1.05;
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}

.has-\[\.work-card-link\:focus-visible\]\:border-\[hsl\(0\2c 0\%\2c 15\%\)\]:has(.work-card-link:focus-visible) {
  --tw-border-opacity: 1;
  border-color: hsl(0 0% 15% / var(--tw-border-opacity, 1));
}

.has-\[\.work-card-link\:hover\]\:border-\[hsl\(0\2c 0\%\2c 15\%\)\]:has(.work-card-link:hover) {
  --tw-border-opacity: 1;
  border-color: hsl(0 0% 15% / var(--tw-border-opacity, 1));
}

.has-\[\.work-card-link\:focus-visible\]\:bg-\[hsl\(0\2c 0\%\2c 5\%\)\]:has(.work-card-link:focus-visible) {
  --tw-bg-opacity: 1;
  background-color: hsl(0 0% 5% / var(--tw-bg-opacity, 1));
}

.has-\[\.work-card-link\:hover\]\:bg-\[hsl\(0\2c 0\%\2c 5\%\)\]:has(.work-card-link:hover) {
  --tw-bg-opacity: 1;
  background-color: hsl(0 0% 5% / var(--tw-bg-opacity, 1));
}

@media (min-width: 640px) {
  .sm\:mx-0 {
    margin-left: 0px;
    margin-right: 0px;
  }

  .sm\:inline-flex {
    display: inline-flex;
  }

  .sm\:w-full {
    width: 100%;
  }

  .sm\:grid-cols-2 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .sm\:justify-end {
    justify-content: flex-end;
  }

  .sm\:rounded-lg {
    border-radius: var(--radius);
  }

  .sm\:border {
    border-width: 1px;
  }

  .sm\:p-4 {
    padding: 1rem;
  }

  .sm\:px-8 {
    padding-left: 2rem;
    padding-right: 2rem;
  }

  .sm\:py-8 {
    padding-top: 2rem;
    padding-bottom: 2rem;
  }

  .sm\:text-right {
    text-align: right;
  }
}

@media (min-width: 768px) {
  .md\:flex {
    display: flex;
  }

  .md\:inline-flex {
    display: inline-flex;
  }

  .md\:hidden {
    display: none;
  }

  .md\:grid-cols-2 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .md\:grid-cols-3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (min-width: 1024px) {
  .lg\:left-\[100px\] {
    left: 100px;
  }

  .lg\:order-1 {
    order: 1;
  }

  .lg\:order-2 {
    order: 2;
  }

  .lg\:col-span-4 {
    grid-column: span 4 / span 4;
  }

  .lg\:-mx-8 {
    margin-left: -2rem;
    margin-right: -2rem;
  }

  .lg\:my-16 {
    margin-top: 4rem;
    margin-bottom: 4rem;
  }

  .lg\:mb-28 {
    margin-bottom: 7rem;
  }

  .lg\:mt-6 {
    margin-top: 1.5rem;
  }

  .lg\:block {
    display: block;
  }

  .lg\:grid {
    display: grid;
  }

  .lg\:hidden {
    display: none;
  }

  .lg\:h-20 {
    height: 5rem;
  }

  .lg\:min-h-0 {
    min-height: 0px;
  }

  .lg\:w-\[76px\] {
    width: 76px;
  }

  .lg\:max-w-none {
    max-width: none;
  }

  .lg\:grid-cols-12 {
    grid-template-columns: repeat(12, minmax(0, 1fr));
  }

  .lg\:grid-cols-2 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .lg\:grid-cols-4 {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .lg\:items-start {
    align-items: flex-start;
  }

  .lg\:gap-10 {
    gap: 2.5rem;
  }

  .lg\:gap-12 {
    gap: 3rem;
  }

  .lg\:gap-16 {
    gap: 4rem;
  }

  .lg\:gap-20 {
    gap: 5rem;
  }

  .lg\:gap-8 {
    gap: 2rem;
  }

  .lg\:gap-\[var\(--space-element\)\] {
    gap: var(--space-element);
  }

  .lg\:space-y-16 > :not([hidden]) ~ :not([hidden]) {
    --tw-space-y-reverse: 0;
    margin-top: calc(4rem * calc(1 - var(--tw-space-y-reverse)));
    margin-bottom: calc(4rem * var(--tw-space-y-reverse));
  }

  .lg\:space-y-24 > :not([hidden]) ~ :not([hidden]) {
    --tw-space-y-reverse: 0;
    margin-top: calc(6rem * calc(1 - var(--tw-space-y-reverse)));
    margin-bottom: calc(6rem * var(--tw-space-y-reverse));
  }

  .lg\:border-l {
    border-left-width: 1px;
  }

  .lg\:border-t-0 {
    border-top-width: 0px;
  }

  .lg\:p-12 {
    padding: 3rem;
  }

  .lg\:p-16 {
    padding: 4rem;
  }

  .lg\:p-7 {
    padding: 1.75rem;
  }

  .lg\:p-8 {
    padding: 2rem;
  }

  .lg\:px-8 {
    padding-left: 2rem;
    padding-right: 2rem;
  }

  .lg\:py-0 {
    padding-top: 0px;
    padding-bottom: 0px;
  }

  .lg\:py-16 {
    padding-top: 4rem;
    padding-bottom: 4rem;
  }

  .lg\:py-20 {
    padding-top: 5rem;
    padding-bottom: 5rem;
  }

  .lg\:py-24 {
    padding-top: 6rem;
    padding-bottom: 6rem;
  }

  .lg\:py-36 {
    padding-top: 9rem;
    padding-bottom: 9rem;
  }

  .lg\:pb-0 {
    padding-bottom: 0px;
  }

  .lg\:pb-12 {
    padding-bottom: 3rem;
  }

  .lg\:pb-32 {
    padding-bottom: 8rem;
  }

  .lg\:pb-\[calc\(env\(safe-area-inset-bottom\2c 0px\)\+1\.5rem\+2\.5rem\+2rem\)\] {
    padding-bottom: calc(env(safe-area-inset-bottom,0px) + 1.5rem + 2.5rem + 2rem);
  }

  .lg\:pl-12 {
    padding-left: 3rem;
  }

  .lg\:pl-\[var\(--space-element\)\] {
    padding-left: var(--space-element);
  }

  .lg\:pt-0 {
    padding-top: 0px;
  }

  .lg\:pt-16 {
    padding-top: 4rem;
  }

  .lg\:pt-24 {
    padding-top: 6rem;
  }

  .lg\:text-2xl {
    font-size: 1.5rem;
    line-height: 2rem;
  }

  .lg\:text-display-lg {
    font-family: var(--font-display);
    font-size: var(--text-display-lg);
    font-weight: 600;
    line-height: 1.1;
    letter-spacing: -0.02em;
  }
}

.\[\&\:\:-webkit-details-marker\]\:hidden::-webkit-details-marker {
  display: none;
}

article:has(.work-card-link:focus-visible) .\[article\:has\(\.work-card-link\:focus-visible\)_\&\]\:border-\[hsl\(210\2c 40\%\2c 98\%\/0\.4\)\] {
  border-color: hsl(210,40%,98%/0.4);
}

article:has(.work-card-link:focus-visible) .\[article\:has\(\.work-card-link\:focus-visible\)_\&\]\:bg-\[hsl\(210\2c 40\%\2c 98\%\)\] {
  --tw-bg-opacity: 1;
  background-color: hsl(210 40% 98% / var(--tw-bg-opacity, 1));
}

article:has(.work-card-link:focus-visible) .\[article\:has\(\.work-card-link\:focus-visible\)_\&\]\:bg-\[hsl\(210\2c 40\%\2c 98\%\/0\.15\)\] {
  background-color: hsl(210,40%,98%/0.15);
}

article:has(.work-card-link:focus-visible) .\[article\:has\(\.work-card-link\:focus-visible\)_\&\]\:text-\[hsl\(0\2c 0\%\2c 5\%\)\] {
  --tw-text-opacity: 1;
  color: hsl(0 0% 5% / var(--tw-text-opacity, 1));
}

article:has(.work-card-link:focus-visible) .\[article\:has\(\.work-card-link\:focus-visible\)_\&\]\:text-\[hsl\(210\2c 40\%\2c 98\%\)\] {
  --tw-text-opacity: 1;
  color: hsl(210 40% 98% / var(--tw-text-opacity, 1));
}

article:has(.work-card-link:focus-visible) .\[article\:has\(\.work-card-link\:focus-visible\)_\&\]\:text-\[hsl\(210\2c 40\%\2c 98\%\/0\.7\)\] {
  color: hsl(210,40%,98%/0.7);
}

article:has(.work-card-link:focus-visible) .\[article\:has\(\.work-card-link\:focus-visible\)_\&\]\:opacity-100 {
  opacity: 1;
}

article:has(.work-card-link:hover) .\[article\:has\(\.work-card-link\:hover\)_\&\]\:border-\[hsl\(210\2c 40\%\2c 98\%\/0\.4\)\] {
  border-color: hsl(210,40%,98%/0.4);
}

article:has(.work-card-link:hover) .\[article\:has\(\.work-card-link\:hover\)_\&\]\:bg-\[hsl\(210\2c 40\%\2c 98\%\)\] {
  --tw-bg-opacity: 1;
  background-color: hsl(210 40% 98% / var(--tw-bg-opacity, 1));
}

article:has(.work-card-link:hover) .\[article\:has\(\.work-card-link\:hover\)_\&\]\:bg-\[hsl\(210\2c 40\%\2c 98\%\/0\.15\)\] {
  background-color: hsl(210,40%,98%/0.15);
}

article:has(.work-card-link:hover) .\[article\:has\(\.work-card-link\:hover\)_\&\]\:text-\[hsl\(0\2c 0\%\2c 5\%\)\] {
  --tw-text-opacity: 1;
  color: hsl(0 0% 5% / var(--tw-text-opacity, 1));
}

article:has(.work-card-link:hover) .\[article\:has\(\.work-card-link\:hover\)_\&\]\:text-\[hsl\(210\2c 40\%\2c 98\%\)\] {
  --tw-text-opacity: 1;
  color: hsl(210 40% 98% / var(--tw-text-opacity, 1));
}

article:has(.work-card-link:hover) .\[article\:has\(\.work-card-link\:hover\)_\&\]\:text-\[hsl\(210\2c 40\%\2c 98\%\/0\.7\)\] {
  color: hsl(210,40%,98%/0.7);
}

article:has(.work-card-link:hover) .\[article\:has\(\.work-card-link\:hover\)_\&\]\:opacity-100 {
  opacity: 1;
}
