/* ==========================================================================
   Boot splash — a VERBATIM port of the GNRS loader.

   Source files:
     GNRS/index.html                       (critical CSS + markup)
     GNRS/src/components/PageLoader.css    (hexagon keyframes, phrase box)

   Colours, geometry, keyframe percentages and animation delays are copied
   exactly: solid black ground, #e74c3c / #c0392b slices, the same 2s cycle with
   the same 5% stagger, the same 0.82s..0.42s reverse-staggered fold-away. Do
   not "improve" the values here — the whole point is that it matches GNRS.

   Only two things are tailored to this site, and neither is styling:
     - the checklist phrases (academic, not government-portal) in PageLoader.tsx
     - the badge text, which carries the profile name instead of the GNRS title

   WHY THIS FILE LIVES IN public/ AND NOT IN src/
   It is linked directly from index.html, so the browser fetches it as a
   render-blocking stylesheet and the splash is fully painted before a single
   byte of the JS bundle runs. Move it into src/ and Vite injects it via
   JavaScript in dev, which reintroduces the white flash this exists to prevent.
   It is therefore NOT processed by PostCSS/autoprefixer — write any prefixes
   you need by hand.

   Bump the ?v= in index.html's <link> whenever this file changes; files in
   public/ are served unhashed and will otherwise sit in the browser cache.
   ========================================================================== */

/* --------------------------------------------------------------------------
   0. Checklist typeface — EB Garamond
   Declared here, from a file in public/fonts/, rather than via @fontsource in
   main.tsx: the splash paints before the bundle exists, so a bundled webfont
   would show Georgia first and then visibly reflow. index.html preloads the
   woff2 so it is ready for the first frame.
   Source: node_modules/@fontsource/eb-garamond (kept as a dependency so the
   file can be refreshed; nothing imports it).
   -------------------------------------------------------------------------- */

@font-face {
  font-family: 'Loader Garamond';
  src: url('/fonts/eb-garamond-latin-500-normal.woff2') format('woff2'),
       url('/fonts/eb-garamond-latin-500-normal.woff') format('woff');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+2122;
}

/* --------------------------------------------------------------------------
   1. Page state
   `data-loading` is stamped on <html> in the markup itself, so the black ground
   is there on the very first paint. PageLoader.tsx removes it when the page is
   ready; an inline failsafe in index.html removes it even if the bundle never
   boots. GNRS drove this with dozens of !important inline styles written from
   JS and re-checked a frame later; one attribute does the same job, and
   removing it hands every rule straight back to index.css.
   -------------------------------------------------------------------------- */

html[data-loading],
html[data-loading] body {
  background-color: #000000;
}

/* A splash should look like an uninterrupted surface — but the scrollbar gutter
   must STAY RESERVED, or the page reflows sideways the moment the real content
   renders (see index.html). So keep the gutter and paint the scrollbar itself
   transparent: the black root background shows through the 15px strip instead
   of a grey track, and it reads as "no scrollbar" while occupying exactly the
   same width.
   Do NOT swap this for `scrollbar-width: none` or `::-webkit-scrollbar {
   display: none }` — those remove the gutter too, and the jump comes back. */
html[data-loading] {
  scrollbar-color: transparent transparent; /* Firefox */
}

html[data-loading]::-webkit-scrollbar,
html[data-loading]::-webkit-scrollbar-track,
html[data-loading]::-webkit-scrollbar-thumb,
html[data-loading]::-webkit-scrollbar-corner {
  background: transparent;
  border: none;
  box-shadow: none;
}

html[data-loading] #root {
  background-color: #000000;
  opacity: 0;
  pointer-events: none;
}

/* GNRS: `body.loaded #root { opacity:1; transition: opacity .5s ease-in-out }` */
html[data-loader-exit] #root {
  opacity: 1;
  transition: opacity 0.5s ease-in-out;
}

/* GNRS: `.loaded #loader-wrapper { opacity:0; transition: opacity .3s ease-out }` */
html:not([data-loading]) #loader-wrapper {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.3s ease-out, visibility 0s 0.3s;
}

/* --------------------------------------------------------------------------
   2. Overlay — GNRS #loader-wrapper / #page
   -------------------------------------------------------------------------- */

#loader-wrapper {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 99999999;
  background: rgba(0, 0, 0, 0.95);
  display: block;
  visibility: visible;
  opacity: 1;
}

#page {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.8);
  opacity: 1;
}

/* --------------------------------------------------------------------------
   3. Badge — GNRS #system-pill, carrying the profile name instead of the
   GNRS system title. Styling is GNRS's, untouched.
   -------------------------------------------------------------------------- */

#system-pill {
  position: absolute;
  top: calc(50% - clamp(140px, 16vh, 180px));
  left: 50%;
  transform: translateX(-50%);
  text-align: center;
  z-index: 10;

  /* DELIBERATE DEVIATION FROM GNRS — two bugs, one fix.
     GNRS used `display: inline-block` with vw-based padding and font-size.
     1. Inline-block meant the badge's height was set by the LINE BOX, which
        includes the parent's strut. The strut takes its metrics from whatever
        font is resolved at that instant, so the badge visibly grew ~3.5px
        mid-splash as webfonts swapped in. `flex` has no strut: height is
        exactly line-height + padding + border, and nothing can move it.
     2. The vw clamps (plus the overrides below) made the badge a different
        size at every breakpoint, and not even monotonically — it was WIDER at
        768px than at 1280px.
     Now: one fixed, legible size everywhere. 1rem/1.4 + 0.55rem/1.15rem
     padding = 42px tall, at every viewport. */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.55rem 1.15rem;
  border-radius: 9999px;
  border: 1px solid rgba(251, 146, 60, 0.3);
  background: linear-gradient(to right, rgba(255, 237, 213, 0.7), rgba(255, 255, 255, 0.9));
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
  transition: transform 0.3s ease;
  white-space: nowrap;
  max-width: calc(100vw - 2rem);
  overflow: hidden;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',
    'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
}

#system-pill h2 {
  font-size: 1rem;
  font-weight: 600;
  color: #152c6a;
  margin: 0;
  padding: 0;
  line-height: 1.4;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  /* `min-width: 0` is what lets text-overflow actually work on a flex child. */
  min-width: 0;
  max-width: 100%;
  font-family: inherit;
}

/* --------------------------------------------------------------------------
   4. Scrolling checklist — GNRS #phrase_box
   -------------------------------------------------------------------------- */

#phrase_box {
  display: flex;
  flex-flow: column;
  width: clamp(250px, 70vw, 340px);
  /* The SVG is 400x200 and scales with `meet`, so the box must hold that same
     2:1 ratio. GNRS clamped width and height independently, which meant the
     scale (and the rendered text size) changed with viewport height and the
     block drifted inside its box. */
  aspect-ratio: 2 / 1;
  max-width: 95vw;
  max-height: 38vh;
  overflow: visible;
}

#phrase_box svg {
  width: 100%;
  height: 100%;
  overflow: visible;
}

#phrase_box text,
#phrase_box tspan {
  font-family: 'Loader Garamond', Garamond, 'EB Garamond', Georgia, 'Times New Roman', serif;
  white-space: nowrap;
  overflow: visible;
  word-wrap: normal;
  word-break: keep-all;
}

/* --------------------------------------------------------------------------
   5. Hexagon — GNRS .preloader / .slice
   Six CSS-border triangles, each rotated a further 60deg about a shared
   bottom-left origin. Every slice runs the same 2s cycle offset by 5%, so they
   unfold 1..6 and fold away 6..1 while the hexagon flips 360deg on Y in two
   discrete steps.
   -------------------------------------------------------------------------- */

#ighex {
  position: fixed;
  bottom: clamp(20px, 4vh, 30px);
  left: 0;
  right: 0;
  display: flex;
  justify-content: center;
}

.preloader {
  position: absolute;
  top: 50%;
  left: 50%;
  display: block;
  font-size: clamp(7px, 1.5vw, 10px);
  width: 3.75em;
  height: 4.25em;
  margin-left: -1.875em;
  margin-top: -2.125em;
  transform-origin: center center;
  transform: rotateY(180deg) rotateZ(-60deg);
  z-index: 10010000;
}

.preloader .slice {
  position: absolute;
  top: 0;
  left: 50%;
  border-top: 1.125em solid transparent;
  border-right: none;
  border-bottom: 1em solid transparent;
  border-left: 1.875em solid #e74c3c;
  border-radius: 3px 3px 0 0;
  transform-origin: left bottom;
}

/* Resting state: reverse-staggered fold-away, GNRS's exact delays. */
.preloader .slice:nth-child(1) {
  transform: rotateZ(60deg) rotateY(0deg) rotateX(0);
  animation: 0.15s linear 0.82s preload-hide-1 both 1;
}
.preloader .slice:nth-child(2) {
  transform: rotateZ(120deg) rotateY(0deg) rotateX(0);
  animation: 0.15s linear 0.74s preload-hide-2 both 1;
}
.preloader .slice:nth-child(3) {
  transform: rotateZ(180deg) rotateY(0deg) rotateX(0);
  animation: 0.15s linear 0.66s preload-hide-3 both 1;
}
.preloader .slice:nth-child(4) {
  transform: rotateZ(240deg) rotateY(0deg) rotateX(0);
  animation: 0.15s linear 0.58s preload-hide-4 both 1;
}
.preloader .slice:nth-child(5) {
  transform: rotateZ(300deg) rotateY(0deg) rotateX(0);
  animation: 0.15s linear 0.5s preload-hide-5 both 1;
}
.preloader .slice:nth-child(6) {
  transform: rotateZ(360deg) rotateY(0deg) rotateX(0);
  animation: 0.15s linear 0.42s preload-hide-6 both 1;
}

.preloader.loading {
  animation: 2s preload-flip steps(2) infinite both;
}

.preloader.loading .slice:nth-child(1) {
  transform: rotateZ(60deg) rotateY(90deg) rotateX(0);
  animation: 2s preload-cycle-1 linear infinite both;
}
.preloader.loading .slice:nth-child(2) {
  transform: rotateZ(120deg) rotateY(90deg) rotateX(0);
  animation: 2s preload-cycle-2 linear infinite both;
}
.preloader.loading .slice:nth-child(3) {
  transform: rotateZ(180deg) rotateY(90deg) rotateX(0);
  animation: 2s preload-cycle-3 linear infinite both;
}
.preloader.loading .slice:nth-child(4) {
  transform: rotateZ(240deg) rotateY(90deg) rotateX(0);
  animation: 2s preload-cycle-4 linear infinite both;
}
.preloader.loading .slice:nth-child(5) {
  transform: rotateZ(300deg) rotateY(90deg) rotateX(0);
  animation: 2s preload-cycle-5 linear infinite both;
}
.preloader.loading .slice:nth-child(6) {
  transform: rotateZ(360deg) rotateY(90deg) rotateX(0);
  animation: 2s preload-cycle-6 linear infinite both;
}

@keyframes preload-flip {
  0%   { transform: rotateY(0deg)   rotateZ(-60deg); }
  100% { transform: rotateY(360deg) rotateZ(-60deg); }
}

@keyframes preload-hide-1 {
  to { transform: rotateZ(60deg)  rotateY(-90deg) rotateX(0deg); border-left-color: #c0392b; }
}
@keyframes preload-hide-2 {
  to { transform: rotateZ(120deg) rotateY(-90deg) rotateX(0deg); border-left-color: #c0392b; }
}
@keyframes preload-hide-3 {
  to { transform: rotateZ(180deg) rotateY(-90deg) rotateX(0deg); border-left-color: #c0392b; }
}
@keyframes preload-hide-4 {
  to { transform: rotateZ(240deg) rotateY(-90deg) rotateX(0deg); border-left-color: #c0392b; }
}
@keyframes preload-hide-5 {
  to { transform: rotateZ(300deg) rotateY(-90deg) rotateX(0deg); border-left-color: #c0392b; }
}
@keyframes preload-hide-6 {
  to { transform: rotateZ(360deg) rotateY(-90deg) rotateX(0deg); border-left-color: #c0392b; }
}

@keyframes preload-cycle-1 {
  5%        { transform: rotateZ(60deg) rotateY(90deg) rotateX(0deg); border-left-color: #c0392b; }
  10%, 75%  { transform: rotateZ(60deg) rotateY(0)     rotateX(0deg); border-left-color: #e74c3c; }
  80%, 100% { transform: rotateZ(60deg) rotateY(90deg) rotateX(0deg); border-left-color: #c0392b; }
}
@keyframes preload-cycle-2 {
  10%       { transform: rotateZ(120deg) rotateY(90deg) rotateX(0deg); border-left-color: #c0392b; }
  15%, 70%  { transform: rotateZ(120deg) rotateY(0)     rotateX(0deg); border-left-color: #e74c3c; }
  75%, 100% { transform: rotateZ(120deg) rotateY(90deg) rotateX(0deg); border-left-color: #c0392b; }
}
@keyframes preload-cycle-3 {
  15%       { transform: rotateZ(180deg) rotateY(90deg) rotateX(0deg); border-left-color: #c0392b; }
  20%, 65%  { transform: rotateZ(180deg) rotateY(0)     rotateX(0deg); border-left-color: #e74c3c; }
  70%, 100% { transform: rotateZ(180deg) rotateY(90deg) rotateX(0deg); border-left-color: #c0392b; }
}
@keyframes preload-cycle-4 {
  20%       { transform: rotateZ(240deg) rotateY(90deg) rotateX(0deg); border-left-color: #c0392b; }
  25%, 60%  { transform: rotateZ(240deg) rotateY(0)     rotateX(0deg); border-left-color: #e74c3c; }
  65%, 100% { transform: rotateZ(240deg) rotateY(90deg) rotateX(0deg); border-left-color: #c0392b; }
}
@keyframes preload-cycle-5 {
  25%       { transform: rotateZ(300deg) rotateY(90deg) rotateX(0deg); border-left-color: #c0392b; }
  30%, 55%  { transform: rotateZ(300deg) rotateY(0)     rotateX(0deg); border-left-color: #e74c3c; }
  60%, 100% { transform: rotateZ(300deg) rotateY(90deg) rotateX(0deg); border-left-color: #c0392b; }
}
@keyframes preload-cycle-6 {
  30%       { transform: rotateZ(360deg) rotateY(90deg) rotateX(0deg); border-left-color: #c0392b; }
  35%, 50%  { transform: rotateZ(360deg) rotateY(0)     rotateX(0deg); border-left-color: #e74c3c; }
  55%, 100% { transform: rotateZ(360deg) rotateY(90deg) rotateX(0deg); border-left-color: #c0392b; }
}

/* --------------------------------------------------------------------------
   6. Responsive — GNRS's exact breakpoints
   -------------------------------------------------------------------------- */

@media (max-width: 768px) {
  #ighex { bottom: clamp(20px, 5vh, 30px); }
  .preloader { font-size: clamp(7px, 2vw, 10px); }
  #phrase_box {
    width: clamp(250px, 75vw, 300px);
    height: clamp(100px, 30vh, 150px);
  }
  /* Position only — the badge keeps its one fixed size at every breakpoint. */
  #system-pill { top: calc(50% - clamp(140px, 16vh, 170px)); }
}

@media (max-width: 480px) {
  #ighex { bottom: clamp(15px, 4vh, 25px); }
  .preloader { font-size: clamp(6px, 1.8vw, 8px); }
  #phrase_box {
    width: clamp(220px, 80vw, 280px);
    height: clamp(80px, 25vh, 120px);
  }
  #system-pill {
    top: calc(50% - clamp(130px, 15vh, 160px));
    max-width: calc(100vw - 1rem);
  }
}

@media (min-width: 1024px) {
  #system-pill { top: calc(50% - clamp(150px, 17vh, 190px)); }
}

/* --------------------------------------------------------------------------
   7. Reduced motion
   Not in GNRS, and not a restyle: the flip and the scroll are vestibular
   triggers, so for readers who ask for less motion the hexagon holds still and
   breathes instead (PageLoader.tsx skips its rAF loop to match). Every colour
   and dimension above is untouched.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .preloader,
  .preloader.loading { transform: rotateZ(-60deg); animation: none; }
  .preloader.loading .slice { animation: preload-breathe 2.4s ease-in-out infinite both; }
  .preloader.loading .slice:nth-child(1) { transform: rotateZ(60deg); }
  .preloader.loading .slice:nth-child(2) { transform: rotateZ(120deg); }
  .preloader.loading .slice:nth-child(3) { transform: rotateZ(180deg); }
  .preloader.loading .slice:nth-child(4) { transform: rotateZ(240deg); }
  .preloader.loading .slice:nth-child(5) { transform: rotateZ(300deg); }
  .preloader.loading .slice:nth-child(6) { transform: rotateZ(360deg); }

  html[data-loader-exit] #root { transition: none; }
  html:not([data-loading]) #loader-wrapper { transition: none; }
}

@keyframes preload-breathe {
  0%, 100% { opacity: 0.4; }
  50%      { opacity: 1; }
}
