/* Senior Thesis — standalone comic reader.
   Fully self-contained: no shared files with the main site or the other
   two comic readers, per project convention (see DANNY-README.md). */

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
}

/* Tiled background + top-to-bottom darkening gradient, per Figma.
   Tile is the image's own native size (750x600) at >=1440px; below
   that it's a uniform 67% scale (~502.5x402) at every narrower width
   — not a continuously scaling tile, just one drop at the 1440 line.
   Lives on body (not .page) so it always fills the full document even
   when .page's own content is shorter than the viewport. */
body {
  background-color: #000;
  background-image: linear-gradient(180deg, rgba(0, 0, 0, 0.5) 0%, rgb(0, 0, 0) 100%), url("images/background.avif");
  background-position: top left;
  background-repeat: repeat;
  background-size: auto, 502.5px 402px;
  font-family: "Comic Neue", cursive;
  color: #fff;
}

@media (min-width: 1440px) {
  body {
    background-size: auto, 750px 600px;
  }
}

a {
  color: inherit;
}

/* ==========================================================
   Scale tiers — pure width cascade, but NOT one clean 3-tier
   system: type scale (title/button/pagination/credit sizes)
   switches at 768 and 1024; spacing (--container-gap,
   --main-content-gap, --page-pb) mostly follows the same steps
   but doesn't fully reach the Desktop values until 1440 — see
   the 1024/1440 blocks below for exactly which variables cut
   over where. --container-gap and --footer-gap look similar but
   are genuinely different measurements per Figma: the first is
   the gap between Main Content and Footer, the second is
   Footer's own internal gap between its nav row and credit
   line — they only happen to share the same value at the
   Tablet-Landscape/Desktop tiers, not at Mobile/Tablet-Portrait.
   (Confirmed against this project's own real numbers, not assumed
   from Turn on the Fun's — the two comics don't cut over at
   exactly the same values, just the same shape of cascade.) */

.page {
  --title-height: 24px;
  --name-size: 12px;
  --frame-pad: 6px;
  --container-gap: 16px;
  --footer-gap: 12px;
  --nav-gap: 8px;
  --nav-button-width: auto;
  --nav-button-flex: 1 1 0%;
  --nav-button-height: 44px;
  --nav-text-size: 16px;
  --pagination-width: 72px;
  --pagination-label-size: 10px;
  --pagination-value-size: 16px;
  --credit-line1-size: 14px;
  --credit-line2-size: 12px;
  --container-padding-inline: 24px;
  --container-max-width: none;
  --main-content-gap: 16px;
  --header-justify: center;
  --header-gap: 24px;
  --page-pt: 16px;
  --page-pb: 12px;
}

@media (min-width: 768px) {
  .page {
    --title-height: 28px;
    --name-size: 14px;
    --frame-pad: 10px;
    --container-gap: 24px;
    --footer-gap: 36px;
    --nav-gap: 24px;
    --nav-button-width: 144px;
    --nav-button-flex: 0 0 auto;
    --nav-text-size: 16px;
    --pagination-width: 96px;
    --credit-line1-size: 14px;
    --credit-line2-size: 12px;
    --container-padding-inline: 48px;
    --header-justify: space-between;
    --page-pt: 20px;
    --page-pb: 24px;
  }
}

/* Type scale (title/button/pagination/credit sizes) jumps to the
   Desktop scale here at 1024, but gap/padding stays at the
   Tablet-Portrait values below — Container gap is genuinely 36px
   here (not Desktop's 48px) and page padding-bottom is genuinely
   24px (not 48px) per Figma, only actually reaching the Desktop
   spacing at 1440. Same two-cascade-point shape as Turn on the Fun. */
@media (min-width: 1024px) {
  .page {
    --title-height: 40px;
    --name-size: 18px;
    --container-gap: 36px;
    --nav-button-width: 200px;
    --nav-button-height: 48px;
    --nav-text-size: 18px;
    --pagination-label-size: 12px;
    --pagination-value-size: 18px;
    --credit-line1-size: 16px;
    --credit-line2-size: 14px;
    --container-max-width: 996px;
    --container-padding-inline: 0;
  }
}

@media (min-width: 1440px) {
  .page {
    --container-gap: 48px;
    --footer-gap: 48px;
    --main-content-gap: 20px;
    --page-pb: 48px;
  }
}

@media (min-width: 1920px) {
  .page {
    --container-max-width: 1200px;
  }
}

/* ==========================================================
   Structure — same markup at every tier, only these rules
   read the variables above.
   ========================================================== */

.page {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: var(--page-pt) 0 var(--page-pb);
}

.container {
  display: flex;
  flex-direction: column;
  gap: var(--container-gap);
  width: 100%;
  max-width: var(--container-max-width);
  padding-inline: var(--container-padding-inline);
}

.main-content {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--main-content-gap);
  width: 100%;
  transition: gap 0.35s ease;
}

/* The cover hides the header — its title+author would just repeat
   what the cover art itself already carries. Collapsed via
   max-height (not display:none) so it can animate open; the
   generous 80px ceiling comfortably covers the header's rendered
   height at every scale tier. main-content's own gap collapses to 0
   alongside it so no empty gap-sized space is left above the image
   while the header is hidden. */
.header {
  display: flex;
  align-items: center;
  justify-content: var(--header-justify);
  gap: var(--header-gap);
  width: 100%;
  max-height: 80px;
  overflow: hidden;
  opacity: 1;
  transition: max-height 0.35s ease, opacity 0.25s ease;
}

.main-content.header-hidden {
  gap: 0;
}

.main-content.header-hidden .header {
  max-height: 0;
  opacity: 0;
}

.header__title {
  display: block;
  height: var(--title-height);
  width: auto;
}

.header__name {
  margin: 0;
  font-family: "Comic Neue", cursive;
  font-weight: 700;
  font-size: var(--name-size);
  line-height: 1.4;
  color: #fff;
  white-space: nowrap;
}

/* aspect-ratio (matching the real page images' own 2700x4173) drives
   sizing directly, instead of relying on the <img>'s intrinsic size
   propagating up through a shrinking flex item — Safari doesn't
   reliably shrink a flex item whose only sizing signal is a nested
   image's own width/height:auto + max-width/max-height, so on a short
   viewport the frame stayed full width there (worked fine in Chrome).
   aspect-ratio is explicitly specified to interact correctly with
   flex/max-height shrinking in all current browsers, sidestepping
   that inconsistency rather than working around it. */
.image-frame {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  aspect-ratio: 2700 / 4173;
  padding: var(--frame-pad);
  background: #fff;
}

.image-frame__img {
  display: block;
  width: 100%;
  height: 100%;
  transition: opacity 0.2s ease-out;
}

.image-frame__loader {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 72px;
  height: 72px;
  transform: translate(-50%, -50%);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s ease-out;
}

@media (min-width: 768px) {
  .image-frame__loader {
    width: 96px;
    height: 96px;
  }
}

.image-frame.is-loading .image-frame__img {
  opacity: 0.05;
}

.image-frame.is-loading .image-frame__loader {
  opacity: 1;
}

.footer {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--footer-gap);
  width: 100%;
}

.navigation {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: var(--nav-gap);
  width: 100%;
}

.nav-button {
  display: flex;
  flex: var(--nav-button-flex);
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: var(--nav-button-width);
  height: var(--nav-button-height);
  padding: 8px 0;
  background: transparent;
  border: 4px solid #fff;
  font-family: "Comic Neue", cursive;
  font-weight: 700;
  font-size: var(--nav-text-size);
  color: #fff;
  text-transform: uppercase;
  cursor: pointer;
}

/* (hover: hover) scopes this to devices with a real hovering pointer
   (mouse/trackpad). Without it, tapping a button on a touchscreen
   matches :hover and — since there's no mouse to move away and clear
   it — the "hover" look sticks around after the tap until something
   else is touched. Gating it here means touch never triggers it at
   all, rather than trying to clear it after the fact. */
@media (hover: hover) {
  .nav-button:hover:not(:disabled) {
    background: #fff;
    color: #000;
  }

  .nav-button:hover:not(:disabled) .nav-button__icon {
    color: #c60003;
  }
}

.nav-button:disabled {
  opacity: 0.3;
  cursor: default;
}

.nav-button__icon {
  display: block;
  color: inherit;
}

.pagination {
  display: flex;
  flex: 0 0 auto;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  width: var(--pagination-width);
  height: var(--nav-button-height);
  padding: 0 36px;
  border-top: 1px solid rgba(255, 255, 255, 0.3);
  border-bottom: 1px solid rgba(255, 255, 255, 0.3);
  font-family: "Comic Neue", cursive;
  font-weight: 700;
  line-height: 1;
  color: #fff;
  text-align: center;
  white-space: nowrap;
}

.pagination__label {
  font-size: var(--pagination-label-size);
}

.pagination__value {
  font-size: var(--pagination-value-size);
}

/* "FRONT / COVER" reads at the same small size as the "PAGE" label,
   not the larger page-number size the counted pages use. */
.pagination__value--cover {
  font-size: var(--pagination-label-size);
}

.credit {
  display: flex;
  flex-direction: column;
  align-items: center;
  line-height: 1.4;
  color: #fff;
  text-align: center;
}

.credit__line1 {
  margin: 0;
  font-family: "Comic Neue", cursive;
  font-weight: 700;
  font-size: var(--credit-line1-size);
}

.credit__line2 {
  margin: 0;
  font-family: "Comic Neue", cursive;
  font-weight: 400;
  font-size: var(--credit-line2-size);
  text-decoration: none;
}

@media (hover: hover) {
  .credit__line2:hover {
    color: #ff9395;
    text-decoration: underline;
    text-decoration-style: solid;
    text-underline-position: from-font;
  }
}

/* ==========================================================
   Constrained mode — everything visible on one screen, footer
   anchored to the bottom. Applies below 768px unconditionally,
   and from 768-1023px only on a touch device (a resized desktop
   browser window in that range has no easy pinch-to-zoom, so it
   gets the natural-flow/scrollable treatment instead — see
   .header override further down for the one piece of this that
   still needs to flip back at that width).

   The mechanism: .page is a fixed 100dvh (dynamic viewport height,
   not 100vh — vh is often taller than what's actually visible on
   mobile browsers once address-bar chrome is accounted for).
   .container and .main-content are both flex:1 with
   justify-content:center, so when their content is SHORTER than
   the space available, it centers as a group with even space
   above/below. When content is TALLER than the space available,
   there's no slack left for justify-content to distribute, so
   .image-frame's flex-shrink (from flex:0 1 auto) takes over and
   it gives up height to fit — .header never shrinks (flex:0 0 auto)
   so only the artwork ever gets smaller. min-height:0 is required
   on anything in that chain that needs to shrink — flex items
   default to min-height:auto, which blocks real shrinking below
   content size.

   Critically .image-frame's flex-GROW stays 0, not 1: growing it
   would stretch the frame's white mat to fill all remaining space
   while the image inside stayed correctly aspect-ratio-sized and
   smaller, leaving a big empty gap of white mat around it. With
   grow:0 the frame only ever takes its natural content size
   (hugging the image tightly) or shrinks below it when space is
   short — it never expands beyond it, so any slack shows up as
   centered space around the whole header+frame group instead of
   empty padding inside the frame.

   .image-frame's own aspect-ratio (not the <img>'s intrinsic size)
   is what makes the shrink preserve proportions and stay centered.
   An earlier version relied on the <img> alone (width/height:auto,
   max-width/max-height:100%) to keep its ratio while the frame
   shrunk around it — Chrome handles that fine, but Safari doesn't
   reliably shrink a flex item whose only sizing signal comes from a
   nested replaced element like that, so the frame stayed full width
   there even though Chrome shrunk it correctly. Declaring the ratio
   directly on the frame itself (interacting with max-height here)
   is explicitly specified to behave consistently across browsers,
   which sidesteps that inconsistency instead of working around it.
   ========================================================== */

@media (max-width: 767px), (min-width: 768px) and (max-width: 1023px) and (pointer: coarse) {
  .page {
    height: 100dvh;
    justify-content: flex-start;
  }

  .container {
    flex: 1 1 auto;
    min-height: 0;
    justify-content: center;
  }

  .main-content {
    flex: 1 1 auto;
    min-height: 0;
    align-items: center;
    justify-content: center;
  }

  .header {
    flex: 0 0 auto;
    justify-content: center;
  }

  .image-frame {
    flex: 0 1 auto;
    width: auto;
    max-width: 100%;
    max-height: 100%;
    min-height: 0;
    min-width: 0;
  }
}
