/* ==========================================================================
   Code of the Geeks — home page
   Two cards on a dark, atmospheric backdrop.

   Geometry is unchanged from the tuned version: both cards are locked to the
   golden ratio (w/h = 1/1.618) via aspect-ratio, content scales through
   container-query units, and there is exactly one stacking breakpoint at
   768px. Everything below adds the FX layer on top of that skeleton.

   Both cards are frosted dark glass and share one surface; the engineering
   and tools cards are distinguished by accent and motif, not by material.
   ========================================================================== */

:root {
  --base: #131317;
  --text: #d7d8dc;
  --text-dim: #9a9ba0;

  /* Per-brand accents, held as RGB triplets so alpha variants can be derived
     anywhere (aurora, halo, rim, motif tint). Swapping these two triplets and
     their light ends re-skins the entire page.

     Engineering is old terminal green — P1 phosphor, the colour of the CRTs
     this company's firmware world grew up on. Tools stays violet. */
  --accent-eng-rgb: 51, 255, 51;
  --accent-eng: rgb(var(--accent-eng-rgb));
  --accent-eng-2: #a6ff9e;

  --accent-tools-rgb: 167, 139, 250;
  --accent-tools: rgb(var(--accent-tools-rgb));
  --accent-tools-2: #c4b5fd;

  --radius: 1.6rem;

  /* Height of everything on the page that is not a card: container padding
     plus footer. The card cap below subtracts this so the pair always fits
     the viewport. Re-measured and tightened on short screens further down. */
  --page-chrome: 16rem;
}

html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

body {
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  /* Dark page, matching the engineering site's monochrome look. */
  background-color: var(--base);
  background-image: radial-gradient(ellipse 130% 85% at 50% -10%, #1c1c22 0%, var(--base) 62%);
  background-attachment: fixed;
  background-repeat: no-repeat;
  color: var(--text);
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}

/* Aurora: two slow-drifting colour fields that give the flat black depth.
   Painted behind the body background (which propagates to the canvas). */
body::before {
  content: "";
  position: fixed;
  inset: -25vmax;
  z-index: -1;
  pointer-events: none;
  background-image:
    radial-gradient(38vmax 38vmax at 24% 26%, rgba(var(--accent-eng-rgb), 0.13), transparent 68%),
    radial-gradient(34vmax 34vmax at 78% 74%, rgba(var(--accent-tools-rgb), 0.13), transparent 68%),
    radial-gradient(26vmax 26vmax at 64% 6%, rgba(var(--accent-eng-rgb), 0.06), transparent 70%);
  animation: auroraDrift 34s ease-in-out infinite alternate;
}

@keyframes auroraDrift {
  0% {
    transform: translate3d(-3%, -2%, 0) scale(1.02);
  }
  50% {
    transform: translate3d(2%, 3%, 0) scale(1.10);
  }
  100% {
    transform: translate3d(4%, -1%, 0) scale(1.04);
  }
}

/* Film grain over everything: kills the banding a large dark gradient shows
   on 8-bit panels and stops the page reading as flat. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  opacity: 0.05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23g)'/%3E%3C/svg%3E");
}

#main-container {
  display: flex;
  align-items: center;
  flex-grow: 1;
  padding-top: 3.5rem;
  padding-bottom: 3.5rem;
}

#card-container {
  width: 100%;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(1rem, 2vw, 2rem);
  padding-left: 1rem;
  padding-right: 1rem;
}

/* Card size tracks the container, and the shape is locked to the golden
   ratio (w/h = 1/1.618) via aspect-ratio so it cannot drift. Content below
   scales with the card through container query units.

   One stacking breakpoint only: below 768px the pair stacks; at and above
   it the two cards share one row as calc(50% - half gap) each, so they
   always fit and never flip-flop with Bootstrap container widths. */
.card-slot {
  position: relative;
  flex: 1 1 100%;
  width: auto;
  max-width: min(100%, 34rem);
  padding-left: 0;
  padding-right: 0;
  margin-left: 0;
  margin-right: 0;
  aspect-ratio: 1 / 1.618;
  container-type: inline-size;

  /* Default accent; the tools slot overrides it. The -rgb triplet is kept
     alongside so alpha variants can be built where a plain colour will not do. */
  --accent: var(--accent-eng);
  --accent-2: var(--accent-eng-2);
  --accent-rgb: var(--accent-eng-rgb);

  animation: cardRise 0.9s cubic-bezier(0.2, 0.7, 0.2, 1) both;
}

.card-slot--eng {
  animation-delay: 0.05s;
}

.card-slot--tools {
  --accent: var(--accent-tools);
  --accent-2: var(--accent-tools-2);
  --accent-rgb: var(--accent-tools-rgb);
  animation-delay: 0.18s;
}

@media (min-width: 768px) {
  .card-slot {
    flex: 1 1 calc(50% - 0.5 * clamp(1rem, 2vw, 2rem));
    /* Keep the golden ratio, but never let a card grow taller than the
       viewport — on short/wide screens the pair shrinks so the buttons stay
       above the fold instead of being cut off. */
    max-width: clamp(16rem, calc((100vh - var(--page-chrome)) / 1.618), 36rem);
  }
}

/* Laptop-height viewports (1366x768, 1440x900 and friends) are too short for
   full-size cards. Reclaim the slack from the page chrome rather than
   shrinking the cards, which keeps them larger *and* above the fold. */
@media (min-width: 768px) and (max-height: 860px) {
  :root {
    /* Measured: footer 144px + container padding 2 x 32px = 208px. 13.5rem
       leaves ~8px of slack so a rounding difference cannot force a scrollbar. */
    --page-chrome: 13.5rem;
  }

  #main-container {
    padding-top: 2rem;
    padding-bottom: 2rem;
  }

  .site-footer {
    padding-top: 1rem;
    padding-bottom: 1.25rem;
  }
}

@keyframes cardRise {
  from {
    opacity: 0;
    transform: translateY(22px) scale(0.985);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* Accent halo bleeding out from behind each card. */
.card-slot::before {
  content: "";
  position: absolute;
  inset: 6% 3% -5% 3%;
  z-index: 0;
  border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(closest-side, var(--accent), transparent 72%);
  opacity: 0.3;
  filter: blur(40px);
  transition: opacity 0.5s ease;
}

.card-slot:hover::before {
  opacity: 0.46;
}

/* ---- Card surface -------------------------------------------------------- */

/* One surface for both cards: frosted glass over the aurora. The two are
   told apart by their accent, not by their material. This used to be split
   across two .card-surface blocks in different sections of this file, which
   made it easy to edit one and forget the other; it is now a single rule. */
.card-surface {
  /* Read by .card-title, .card-description and .card-surface::after below. */
  --fg: #f2f3f6;
  --fg-dim: #b6b9c4;
  --spot: rgba(255, 255, 255, 0.09);

  position: relative;
  z-index: 1;
  height: 100%;
  /* Padding scales with the card so the ratio holds at every size. */
  padding: 8cqw;
  border-radius: var(--radius);
  color: #f2f3f6;
  box-shadow:
    0 30px 60px -30px rgba(0, 0, 0, 0.9),
    0 2px 6px rgba(0, 0, 0, 0.35);
  background-image:
    var(--card-wash, linear-gradient(transparent, transparent)),
    linear-gradient(165deg,
      rgba(255, 255, 255, 0.085),
      rgba(255, 255, 255, 0.022) 42%,
      rgba(255, 255, 255, 0.045)),
    linear-gradient(rgba(19, 19, 24, 0.52), rgba(19, 19, 24, 0.6));
  -webkit-backdrop-filter: blur(16px) saturate(135%);
  backdrop-filter: blur(16px) saturate(135%);
  transition:
    transform 0.45s cubic-bezier(0.2, 0.7, 0.2, 1),
    box-shadow 0.45s ease;
}

.card-slot:hover .card-surface {
  transform: translateY(-6px);
  box-shadow:
    0 44px 80px -32px rgba(0, 0, 0, 0.95),
    0 0 60px -28px var(--accent);
}

/* Static hairline rim. This is what reads the glass edge against the dark
   page, and it is all that is left of the card border: a bright arc used to
   travel around it, which pulled the eye to the frame instead of the content. */
.card-surface::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  border-radius: inherit;
  padding: 1px;
  pointer-events: none;
  background: linear-gradient(165deg,
      rgba(255, 255, 255, 0.22),
      rgba(255, 255, 255, 0.05) 42%,
      rgba(255, 255, 255, 0.02));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
}

/* Pointer-follow spotlight. */
.card-surface::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.4s ease;
  background: radial-gradient(20rem 20rem at var(--mx, 50%) var(--my, 0%),
      var(--spot),
      transparent 62%);
}

.card-slot:hover .card-surface::after {
  opacity: 1;
}

/* The tools mark is black artwork on what is now a dark card, so it is
   inverted to white. It is a pure monochrome mark, so this is lossless. */
.card-slot--tools .card-logo img {
  filter: invert(1) brightness(1.06);
}

/* ---- Decorative motifs --------------------------------------------------- */

.card-motif {
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  overflow: hidden;
  pointer-events: none;
}

/* A wash of each card's own accent across its top edge, so the two brands
   stay distinguishable even though both surfaces are the same glass. Painted
   as the topmost background layer of the surface itself, which keeps the motif
   slot free for the one motif each card actually has.
   Green carries roughly twice the luminance of violet at the same alpha, so it
   gets a lower value to land at the same perceived strength. */
.card-slot--eng {
  --card-wash: radial-gradient(125% 70% at 50% -12%, rgba(var(--accent-eng-rgb), 0.12), transparent 72%);
}

.card-slot--tools {
  --card-wash: radial-gradient(125% 70% at 50% -12%, rgba(var(--accent-tools-rgb), 0.2), transparent 72%);
}

/* Engineering: a terminal prompt sitting in the same bottom band as the level
   meter, so the two cards mirror each other. No window chrome and no frame — a
   prompt line reads as a shell and stays in keeping with how stripped back the
   rest of the page is.

   It wraps at spaces like a real terminal rather than being held to one line.
   That is what lets a 43-character one-liner coexist with a readable font: the
   alternative was a 2.4cqw font, about 6px at the smallest card. The box is
   anchored to the bottom and grows upward, capped at two rows; a third would
   reach the button. */
.motif-term {
  top: auto;
  left: 8cqw;
  right: 8cqw;
  bottom: 8cqw;
  height: auto;
  max-height: 7cqw;
  overflow: hidden;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 2.7cqw;
  line-height: 1.25;
  overflow-wrap: normal;
  word-break: normal;
  color: rgba(var(--accent-eng-rgb), 0.9);
}

.card-term__prompt {
  opacity: 0.65;
}

.card-term__cursor {
  display: inline-block;
  width: 0.55em;
  height: 1em;
  margin-left: 0.1em;
  background: currentColor;
  animation: termBlink 1.05s step-end infinite;
}

@keyframes termBlink {
  0% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
}

/* Tools: a level meter breathing along the bottom edge. Kept to a shallow
   strip so it reads as a glow under the card rather than a fence across it. */
.motif-eq {
  top: auto;
  height: 24%;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 1.1cqw;
  padding: 0 7cqw;
  -webkit-mask-image: linear-gradient(to top, #000 0%, transparent 92%);
  mask-image: linear-gradient(to top, #000 0%, transparent 92%);
}

.motif-eq span {
  flex: 1 1 auto;
  max-width: 1.8cqw;
  height: 100%;
  border-radius: 999px;
  background-image: linear-gradient(to top, var(--accent), var(--accent-2));
  transform-origin: 50% 100%;
  /* Base height for the static case: the keyframes are the only thing that
     would otherwise hold the bars down, so with animation off (reduced
     motion) they would stand at full strip height and cut through the text. */
  transform: scaleY(0.12);
  opacity: 0.34;
  animation: eqPulse ease-in-out infinite alternate;
}

@keyframes eqPulse {
  from {
    transform: scaleY(0.03);
  }
  to {
    transform: scaleY(0.2);
  }
}

/* Content sits above the motif. */
.card-surface .row.h-100 {
  position: relative;
  z-index: 1;
}

/* ---- Card contents ------------------------------------------------------ */

/* The two cards share one vertical stack: logo band, title/description
   band, then the button pinned to the bottom.

   flex-wrap must be pinned to nowrap: Bootstrap's .row is wrap, and in a
   *column* flex container wrapping means "start a new column to the right".
   With wrap left on, any overflow silently laid the button out beside the
   card instead of below it. */
#card-container .row.h-100 {
  display: flex;
  flex-direction: column;
  flex-wrap: nowrap;
}

#card-container .card-logo {
  /* The logos are portrait marks, so the band's height is what sets their
     size: the image fills it and the width follows. The assets have had
     their transparent padding trimmed, so the mark fills this band edge to
     edge — at 58cqw the visible logo is ~24% larger than the old 52cqw band
     ever showed. The band cannot grow further without pushing the stack past
     the card's fixed height. */
  height: 58cqw;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 3cqw;
  flex-shrink: 0;
}

#card-container .card-logo img {
  max-height: 100%;
  width: auto;
  object-fit: contain;
}

/* The title sits on a fixed line across both cards; the description is
   centred in the space beneath it, so cards with a longer description stay
   balanced without dragging their title out of line. */
#card-container .card-text {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  padding-top: 2cqw;
  min-height: 0;
}

#card-container .card-text .card-description {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 3cqw 0 4cqw;
}

#card-container .card-action {
  margin-top: auto;
  /* Clearance for the level meter rising from the bottom edge of the tools
     card, so the button never looks glued to it. */
  padding-bottom: 10cqw;
  flex-shrink: 0;
}

.card-title {
  /* Scales with the card (container width), matching the c499a7 proportions. */
  font-size: clamp(1.35rem, 11cqw, 2.833rem);
  font-weight: bold;
  text-transform: none;
  color: var(--fg);
  /* This is an <h2> so the card has a real heading; Bootstrap gives headings
     margin-bottom: 0.5rem, which would push the description down and break the
     two cards' alignment. Size, weight and line-height are already overridden
     above, so the margin is the only heading default left to clear. */
  margin: 0;
  /* Two lines are reserved whether or not a title needs them.
     "Code of the Geeks B.V." wraps at large card sizes where "Free Online
     Tools" fits on one line, so without this reservation the description under
     one card starts a line lower than the description under the other -- the
     pair looks broken beside each other. The buttons stay aligned either way,
     since they are pinned to the bottom.
     line-height is stated rather than inherited so the reserved height and the
     text's real height cannot drift apart; 1.5 is the value it inherited. */
  line-height: 1.5;
  min-height: 3em;
}

.card-description {
  font-size: clamp(1.05rem, 6.5cqw, 1.667rem);
  font-weight: bold;
  text-transform: none;
  color: var(--fg-dim);
}

/* ---- Button ------------------------------------------------------------- */

/* White, like the wordmarks and the body text, so the button belongs to the
   card instead of sitting on it as a separate coloured object. The accent
   still shows up as a soft halo on hover. */
.card-button {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
  padding: 3.2cqw 7cqw;
  border-radius: 999px;
  font-size: clamp(1rem, 5.2cqw, 1.45rem);
  font-weight: bold;
  line-height: 1;
  text-align: center;
  text-decoration: none;
  color: #101016;
  background-image: linear-gradient(180deg, #ffffff, #e8e9ee);
  box-shadow:
    0 10px 26px -14px rgba(0, 0, 0, 0.9),
    inset 0 1px 0 #ffffff;
  transition:
    transform 0.3s cubic-bezier(0.2, 0.7, 0.2, 1),
    filter 0.3s ease,
    box-shadow 0.3s ease;
}

.card-button::after {
  content: "→";
  font-size: 1.05em;
  transition: transform 0.3s cubic-bezier(0.2, 0.7, 0.2, 1);
}

.card-button:hover,
.card-button:focus-visible {
  color: #101016;
  transform: translateY(-2px);
  filter: brightness(1.03);
  box-shadow:
    0 16px 34px -14px rgba(0, 0, 0, 0.95),
    0 0 26px -6px rgba(var(--accent-rgb), 0.55),
    inset 0 1px 0 #ffffff;
}

.card-button:hover::after,
.card-button:focus-visible::after {
  transform: translateX(4px);
}

/* Footer sits on the dark page; Bootstrap Lux links are dark-on-light and
   would disappear here. */
.site-footer {
  padding-top: 1.5rem;
  padding-bottom: 2.5rem;
  color: var(--text-dim);
}

.site-footer a {
  color: #c9cad0;
  text-decoration: underline;
}

.site-footer a:hover {
  color: #ffffff;
}

/* Mobile: a little more top padding and slightly roomier buttons. */
@media (max-width: 767px) {
  #main-container {
    padding-top: 2.25rem;
    padding-bottom: 2.25rem;
  }

  .card-button {
    padding: 12px 28px;
  }
}

/* Motion is decoration here, never information. */
@media (prefers-reduced-motion: reduce) {
  body::before,
  .card-slot,
  .motif-eq span,
  .card-term__cursor {
    animation: none !important;
  }

  .card-slot {
    opacity: 1;
    transform: none;
  }

  .card-surface,
  .card-slot::before,
  .card-surface::after,
  .card-button,
  .card-button::after {
    transition: none !important;
  }

  .card-slot:hover .card-surface {
    transform: none;
  }
}
