/* ── OROK Group ─────────────────────────────────────────────────
   Brand tokens carry over from the OROK Engineering design system so
   the two sites read as siblings. The accent here is the GROUP red
   #F54619, the colour in the group logo; the companies keep theirs.

   Layout: a first screen that holds only the mark and the statement,
   with the companies riding up into its lower half.
   ────────────────────────────────────────────────────────────── */
:root {
  --black:  #000000;
  --glow:   #2F2D29;   /* warm grey the bottom spotlight lifts to */
  --cream:  #FCFAF2;

  --on-dark:    #FCFAF2;
  --copy:       #A39B91;   /* warm grey for body copy on black */
  --copy-lift:  #CBC5BC;   /* the hero statement, a step brighter */
  --copy-dim:   #6F6862;
  --on-dark-fx: rgba(252, 250, 242, 0.26);

  --red:   #F54619;   /* OROK Group */
  --gold:  #FAB417;   /* OROK Engineering */
  --burgundy: #800020;   /* OROK Trading, the K in its wordmark */

  --r-pill: 999px;
  --r-lg:   20px;

  --fs-body:  17px;
  --fs-label: 11px;
  --ls-tight: -0.02em;

  --sp-3: 16px;
  --sp-4: 24px;
  --sp-5: 32px;
  --sp-6: 56px;
  --sp-7: 96px;

  --shell:  1240px;
  --gutter: 40px;


  /* ── the mark sizes ───────────────────────────────────────────
     RULE: the group mark is always larger than a company mark, at every
     size. Sizing the boxes separately to "look right" once had them at
     96px and 90px of actual ring on a short window, which is a tie.

     So there is one number, and the company mark is derived from it.
     The 2026-09-24 lockups are all cropped to the ink, so the ring is
     the full width of every one of them and box width is ring width.
     Re-measure that before trusting it if the artwork changes again.
     0.663 holds the ring ratio at about 1.5x (185 against 124 at full
     height), by construction, at every size. */
  --mark: clamp(111px, min(13.6vw, 17.3svh), 220px);
  --mark-company: calc(var(--mark) * 0.663);

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

@media (max-width: 900px) { :root { --gutter: 28px; } }
@media (max-width: 600px) { :root { --gutter: 18px; --fs-body: 15px; } }

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

html { scroll-behavior: smooth; }

html, body {
  margin: 0;
  padding: 0;
  min-height: 100%;
  background: var(--black);
  color: var(--on-dark);
  font-family: Geist, ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  font-size: var(--fs-body);
  line-height: 1.5;
  letter-spacing: var(--ls-tight);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body { overflow-x: hidden; }

h1 { margin: 0; }
p  { margin: 0; }
a  { color: inherit; text-decoration: none; }
img, svg { display: block; max-width: 100%; }

::selection { background: var(--red); color: var(--cream); }
:focus-visible { outline: 2px solid var(--red); outline-offset: 4px; border-radius: 4px; }

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

/* ── first screen ───────────────────────────────────────────────── */
.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding-inline: var(--gutter);
  /* Only a floor. The real spacing above the mark is an auto margin on
     the lockup, matching the one that pins the companies to the floor, so
     the leftover height splits evenly above and below the statement. A
     tall screen gets the same composition a fixed padding gave it, and a
     short one reclaims the whole gap instead of scrolling. */
  padding-top: clamp(24px, 4svh, 64px);
  overflow: hidden;
  isolation: isolate;
}

/* light rising out of the bottom centre, not a top-down wash */
.glow {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(62% 58% at 50% 100%, var(--glow) 0%, #161513 45%, var(--black) 100%);
}

/* pulls the corners back down so the centre reads as lit */
.vignette {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  /* an ellipse, not a circle: on a tall screen a circular stop only
     reaches full black past the corners, which leaves the whole lower
     middle of the haze lit */
  background:
    radial-gradient(78% 62% at 50% 40%,
      rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.55) 62%, rgba(0, 0, 0, 0.94) 100%);
}

/* ── the mark ─────────────────────────────────────── */
.hero__lockup {
  position: relative;
  z-index: 2;
  margin-top: auto;
  width: var(--mark);
  height: auto;
}

/* ── the particle field behind the first screen ─────────────────── */
.hero__field {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  pointer-events: none;
  transition: opacity 1.2s var(--ease);
}

.hero__field.is-live { opacity: 1; }

/* The vignette stays up now. The haze it replaced drew its own falloff
   into the shader, but the field is additive dots with nothing between
   them, so the corners need pulling down in CSS or the dust reads flat
   from edge to edge. It sits above the canvas for that reason.

   Softer than the fallback version, though: that one is darkening a
   continuous gradient, where this one is darkening individual points,
   and at 0.55 in the mid-stop it ate the shoulders of the two nearest
   elements instead of just settling the corners. */
.hero__field.is-live ~ .vignette {
  z-index: 1;
  background:
    radial-gradient(86% 72% at 50% 42%,
      rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.30) 64%, rgba(0, 0, 0, 0.82) 100%);
}

/* The breaks in the copy are authored, not incidental, so the measure has
   to be wide enough to hold the longest of those lines. width: max-content
   makes each paragraph exactly as wide as its own widest line and no
   wider, which keeps the block centred and ragged the way it is written
   rather than justified out to a fixed column. */
.hero__copy {
  position: relative;
  z-index: 2;
  margin-top: clamp(18px, 4svh, 42px);
  /* the size lives on the block, not the paragraphs, so the measure and
     the paragraph gap below can both be set in em and track it */
  font-size: clamp(15px, 1.1vw, 19px);
  display: grid;
  /* minmax(0, 1fr), not the default auto: an auto track sizes to the
     max-content of its items, so the paragraphs below would size the track
     past the container's max-width and hang off both edges instead of
     wrapping. Pairing it with an explicit width gives max-width something
     bounded to cap. */
  grid-template-columns: minmax(0, 1fr);
  justify-items: center;
  gap: min(1.9em, 4svh);
  width: 100%;
  /* Tuned, not picked: the authored first line measures 450px here, so the
     measure has to clear that, and the second sentence has to divide
     without stranding its last word. 24em to 25em all split it
     450 / 492 / 487; 24.5em sits in the middle of that band so a small
     font-metric difference elsewhere will not tip it either way. */
  max-width: 24.5em;
}

.hero__copy p {
  width: max-content;
  max-width: 100%;
}

/* Below this the first authored line no longer fits the screen, so the
   breaks come out and the copy wraps on the measure alone. */
@media (max-width: 800px) {
  .hero__copy br { display: none; }
}

/* one inline-block per word, so that splitting each word into per-letter
   spans for the heat sweep cannot break it mid-way */
.hero__copy .w { display: inline-block; white-space: nowrap; }

.hero__copy p {
  font-size: inherit;
  font-weight: 700;
  line-height: 1.32;
  letter-spacing: var(--ls-tight);
  color: var(--copy-lift);
}

/* Short windows. The svh-scaled rhythm above gets most of the way there,
   but the mark and the card artwork are still sized for a tall screen and
   leave nothing for the gap above the companies. These bind below 1150px
   tall; a full-height display keeps the composition untouched, where the
   auto margins have slack to give and the gap is already ~96px. */
@media (max-height: 1150px) {
  /* one number moves and the company marks follow it down, so the size
     rule holds here without a second rule to keep in step */
  :root { --mark: clamp(93px, min(13.6vw, 13.6svh), 179px); }

  .hero__copy { margin-top: clamp(14px, 2.4svh, 24px); }
  .division { padding: clamp(14px, 2svh, 24px) var(--sp-4); }
  .foot { margin-top: clamp(20px, 3svh, 40px); }
}

/* ── the companies ────────────────────────────────────────────── */
.companies {
  /* auto, not a negative margin: the section is a flex child of the hero
     now, so this pins it to the floor of the 100svh box and the gap above
     it is simply whatever is left over. The page fits one screen by
     construction rather than by a lift number that has to be re-tuned
     every time the copy changes length. */
  margin-top: auto;
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: var(--shell);
  /* The top padding is the guaranteed gap between the statement and the
     label. margin-top: auto alone is not enough: when the content fills
     the screen the auto collapses to nothing and the two end up 3px
     apart. Padding cannot be squeezed, so the gap survives.
     The hero supplies the side gutter, hence no inline padding. */
  padding: clamp(40px, 5svh, 96px) 0 clamp(14px, 2svh, 24px);
}


.divisions {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-3);
  max-width: 660px;
  margin-inline: auto;
}

.division {
  --tint: 252, 250, 242;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(9px, 1.6svh, 16px);
  padding: clamp(16px, 2.6svh, 32px) var(--sp-4);
  border-radius: var(--r-lg);
  border: 1px solid rgba(252, 250, 242, 0.10);
  /* frosted, now that the wordmark runs behind them: the tint stays in
     background-image so hover can swap it without losing the dark base,
     and the blur is what keeps the letters from reading as dirt through
     the panel. */
  background-color: rgba(6, 6, 6, 0.58);
  background-image: linear-gradient(180deg, rgba(var(--tint), 0.05) 0%, rgba(var(--tint), 0.015) 100%);
  backdrop-filter: blur(26px) saturate(115%);
  -webkit-backdrop-filter: blur(26px) saturate(115%);
  text-align: center;
  color: var(--on-dark);
  transition: border-color 0.5s var(--ease), background-color 0.5s var(--ease),
              background-image 0.5s var(--ease), box-shadow 0.5s var(--ease),
              transform 0.5s var(--ease);
}

/* The card does not move. It lights: border, wash and the beam on top of
   them, and nothing shifts position under the cursor. (There was a
   translateY here; it is deliberately gone, not lost. .in would have
   needed .division.in:hover to beat it on the cascade anyway.) */
.division:hover,
a.division:focus-visible {
  border-color: rgba(var(--tint), 0.30);
  background-color: rgba(6, 6, 6, 0.54);
  /* the wash stays quiet on purpose. At 0.16 it flooded the card brown and
     the beam had nothing to be brighter than; the light is the event here,
     the panel only has to warm up under it. */
  background-image: linear-gradient(180deg, rgba(var(--tint), 0.10) 0%, rgba(var(--tint), 0.028) 100%);
  box-shadow: 0 18px 46px -22px rgba(var(--tint), 0.5);
}

.division--engineering { --tint: 250, 180, 23; }
.division--trading     { --tint: 128, 0, 32; }

/* ── the running light ───────────────────────────────────────────
   A comet traced around the card border on hover: a white tip, a core
   burning in the company colour, and a tail that fades out over roughly
   a quarter of the perimeter.

   Two things make it survive any card size. pathLength="1000" restates
   the rect's perimeter as 1000 units, so every dash length below is a
   per-mille of the border and never has to know the real geometry. And
   the rect's box is set in CSS geometry properties rather than
   attributes, so calc() can inset it by half the stroke and the corner
   radius can track --r-lg exactly. The SVG carries no viewBox on
   purpose: user units are then CSS pixels, so nothing is scaled and the
   radius cannot go oval on a non-square card.

   The tail is built from six nested dashes sharing a leading edge, each
   longer and fainter than the last. Their alphas are picked so the
   composite falls off smoothly rather than in the four visible steps the
   earlier version had: 0.95, 0.80, 0.58, 0.36, 0.18, 0.06.

   The glow is the other half of the fix. It used to sit on the whole
   <svg>, so the faint 260-unit tail bloomed exactly as hard as the tip
   and the whole thing read as a smear. Now only the tip and the two
   densest tail layers carry a drop-shadow, which is what gives the light
   a point of origin. ─────────────────────────────────────────────── */
.division__beam {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* the glow has to be allowed past the border it is drawn on, or the
     SVG clips the bloom flat against the card edge */
  overflow: visible;
  pointer-events: none;
  opacity: 0;
  /* a rect path runs clockwise from the top-left, and animating the
     offset upward walks the dash backwards along it. Mirroring the whole
     svg turns that into a clockwise run without touching the dash maths,
     which is what keeps the tip in front of its own tail. The card is
     symmetric, so the flip is invisible; only the direction changes. */
  transform: scaleX(-1);
  /* quick to ignite, slow to die */
  transition: opacity 0.5s var(--ease);
}

.division:hover .division__beam,
a.division:focus-visible .division__beam {
  opacity: 1;
  transition-duration: 0.18s;
}

.division__beam rect {
  x: 0.75px;
  y: 0.75px;
  width: calc(100% - 1.5px);
  height: calc(100% - 1.5px);
  rx: calc(var(--r-lg) - 0.75px);
  fill: none;
  stroke-linecap: round;
}

/* the run starts on hover rather than free-wheeling underneath an
   invisible card, so the light always enters from the same corner
   instead of fading up wherever it happened to be */
.division:hover .division__beam rect,
a.division:focus-visible .division__beam rect {
  animation: beam-sweep 3.1s linear infinite;
}

@keyframes beam-sweep {
  from { stroke-dashoffset: 0; }
  to   { stroke-dashoffset: 1000; }
}

/* ── the tail, faintest first so the tip paints last ── */
.beam-t6 { stroke: rgb(var(--tint)); stroke-width: 0.9;  stroke-dasharray: 242 758; opacity: 0.06; }
.beam-t5 { stroke: rgb(var(--tint)); stroke-width: 1.05; stroke-dasharray: 170 830; opacity: 0.13; }
.beam-t4 { stroke: rgb(var(--tint)); stroke-width: 1.2;  stroke-dasharray: 115 885; opacity: 0.22; }
.beam-t3 { stroke: rgb(var(--tint)); stroke-width: 1.3;  stroke-dasharray:  72 928; opacity: 0.34; }

/* dense enough to bloom: these two carry the colour */
.beam-t2 {
  stroke: rgb(var(--tint));
  stroke-width: 1.4;
  stroke-dasharray: 38 962;
  opacity: 0.52;
  filter: drop-shadow(0 0 7px rgba(var(--tint), 0.45));
}

.beam-t1 {
  stroke: rgb(var(--tint));
  stroke-width: 1.5;
  stroke-dasharray: 15 985;
  opacity: 0.75;
  filter: drop-shadow(0 0 5px rgba(var(--tint), 0.8));
}

/* the tip: white, short, and the only thing allowed to flare */
.beam-head {
  stroke: #ffffff;
  stroke-width: 1.6;
  stroke-dasharray: 10 990;
  opacity: 1;
  filter: drop-shadow(0 0 2px rgba(255, 255, 255, 0.9))
          drop-shadow(0 0 7px rgb(var(--tint)))
          drop-shadow(0 0 16px rgba(var(--tint), 0.7));
}

.division__lockup { width: 100%; max-width: var(--mark-company); height: auto; }

.division__what {
  font-size: 14px;
  line-height: 1.4;
  color: var(--copy);
  max-width: 30ch;
}

/* a labelled pill on both cards, so "Visit" and "Soon" read as the same
   kind of thing and the two sit level */
.division__go {
  /* the card is a flex column, so auto pushes the pill to its floor and
     the two line up even though one description runs a line longer */
  margin-top: auto;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 30px;
  padding: 0 13px;
  border-radius: var(--r-pill);
  border: 1px solid rgba(252, 250, 242, 0.18);
  color: var(--copy);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  transition: color 0.4s var(--ease), border-color 0.4s var(--ease),
              background-color 0.4s var(--ease);
}

.division__go svg {
  flex: none;
  transition: transform 0.4s var(--ease);
}

.division:hover .division__go,
a.division:focus-visible .division__go {
  color: var(--on-dark);
  border-color: rgba(var(--tint), 0.6);
  background-color: rgba(var(--tint), 0.10);
}

/* the arrow travels, not the whole pill: moving the pill shifts its own
   label along with it, which reads as a wobble rather than a direction */
.division:hover .division__go svg,
a.division:focus-visible .division__go svg { transform: translateX(3px); }

@media (max-width: 600px) {
  .companies { padding-top: var(--sp-6); }
  .divisions { grid-template-columns: 1fr; max-width: 380px; }
  .division { padding: var(--sp-5) var(--sp-3); gap: var(--sp-3); }
  .division__lockup { max-width: min(140px, var(--mark-company)); }
}

/* ── foot ───────────────────────────────────────────────────────── */
.foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  flex-wrap: wrap;
  margin-top: clamp(22px, 4.4svh, 56px);
  padding-top: clamp(14px, 1.9svh, 24px);
  border-top: 1px solid rgba(252, 250, 242, 0.08);
  font-size: var(--fs-label);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--on-dark-fx);
}

.foot a { transition: color 0.3s var(--ease); }
.foot a:hover { color: var(--on-dark); }

@media (max-width: 600px) { .foot { justify-content: center; text-align: center; } }

/* ── entrance ───────────────────────────────────────────────────── */
.rise {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.8s var(--ease), transform 0.8s var(--ease);
  transition-delay: calc(var(--i, 0) * 70ms + 150ms);
}

.is-ready .rise { opacity: 1; transform: none; }

/* below the fold: revealed on scroll rather than on load */
.division,
.foot {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.8s var(--ease), transform 0.8s var(--ease),
              border-color 0.5s var(--ease), background-color 0.5s var(--ease),
              background-image 0.5s var(--ease), box-shadow 0.5s var(--ease);
  transition-delay: calc(var(--i, 0) * 80ms);
}

.division.in,
.foot.in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
    transition-delay: 0s !important;
  }
  .rise, .division, .foot { opacity: 1; transform: none; }

  /* the global animation kill would freeze the comet at one corner, which
     reads as a defect. Drop the run and let the hovered border carry the
     state on its own. */
  .division__beam { display: none; }
  .division:hover,
  .division.in:hover,
  a.division:focus-visible { border-color: rgba(var(--tint), 0.55); }
}
