/* ── Graphic Design: the posters, printed ─────────────────
   Nga's second note settled what the first one meant: "ghép ảnh các poster của
   tôi vào các tạp chí như ảnh mẫu tôi gửi nhưng theo vibe fairy." Put the
   posters INTO the magazines, don't lay them out beside one. So there are four
   printed objects here and each one carries a poster the way a printed thing
   carries it: a cover with a masthead over it, an open spread with the credit
   on the facing page, a loose sheet catching the light, and a plate mounted on
   a dotted back page. Four posters, four objects, nothing shown twice.

   The fairy vocabulary is the site's own, not the mockup's: the hero's lily
   behind the whole desk, a vine printed down the spread's outer edge, a leaf
   rule under a caption, and green/pink carried as light rather than as borders.

   `--lean` is a rotateY. A magazine on a table is seen from an angle, and a
   flat rotate() alone makes paper read as a sticker. Straightening on hover is
   the gesture that matches: you pick a magazine up to look at it square on.

   The overlap is grid areas SHARING CELLS, not absolute positioning, so the
   stage scales with its column instead of coming apart under 1200px. Below
   901px there is no stage: the spread unfolds into one page above the other,
   because a two-page spread 190px wide is not a spread, and the objects become
   a single column keeping only their tilt. */
#design { background: var(--cream); }

.ps-desk { position: relative; margin-top: 1.8rem; }

/* Pink top-left, sage bottom-right. The green-and-pink tone is carried as
   light, so it colours the section without putting a border on anything. */
.ps-desk::before {
  content: ''; position: absolute; inset: -12% -9%; z-index: 0; pointer-events: none;
  background:
    radial-gradient(46% 40% at 20% 16%, rgba(212,168,180,0.36), transparent 72%),
    radial-gradient(50% 44% at 84% 84%, rgba(139,158,122,0.32), transparent 74%);
  filter: blur(26px);
}

/* The hero's own lily, blown up to the height of the desk and taken almost to
   nothing. Borrowing the cut-out the site already uses is what keeps this
   section inside the same fairy language as the rest of the page. */
.ps-watermark {
  position: absolute; z-index: 0; pointer-events: none; user-select: none;
  width: min(620px, 78%); left: 50%; top: 48%;
  transform: translate(-50%, -50%) rotate(-9deg);
  opacity: 0.14;
}

.ps-scatter {
  position: relative; z-index: 1; display: grid;
  gap: 2.1rem; max-width: 520px; margin: 0 auto;
}

/* ── what every printed object shares ──────────────────── */
.ps-piece {
  position: relative; margin: 0;
  transform: perspective(1500px) rotateY(var(--lean, 0deg)) rotate(var(--tilt, 0deg));
  transition: transform 0.45s cubic-bezier(0.34,1.56,0.64,1), box-shadow 0.45s;
}
/* Picking one up is delight, not an affordance: none of these open anything,
   so none of them claims a pointer it cannot honour. */
.ps-piece:hover { transform: perspective(1500px) rotateY(0deg) rotate(0deg) translateY(-10px) scale(1.02); z-index: 20; }

/* Paper is a stack, and the stack is what says "magazine" rather than "photo":
   two offset sheets under the top one, then the shadow the whole block casts. */
.ps-paper {
  position: relative; background: var(--card-bg);
  box-shadow:
    2px 2px 0 -1px var(--parch), 3px 3px 0 -1px rgba(92,61,46,0.13),
    5px 5px 0 -1px var(--parch), 6px 6px 0 -1px rgba(92,61,46,0.11),
    9px 20px 44px rgba(92,61,46,0.20);
}

.ps-frame { display: block; overflow: hidden; background: var(--parch); }
.ps-frame img { width: 100%; height: 100%; display: block; object-fit: cover; }

/* Printed ornament: on the page, under the ink, never on top of it. */
.ps-orn { position: absolute; pointer-events: none; user-select: none; z-index: 0; }

/* ── the cover, closed and standing ────────────────────── */
.ps-cover .ps-paper {
  padding: 12px 12px 0;
  border-radius: 1px 4px 4px 1px;
}
/* The spine is a fold in the paper, not a rail on a card. It is the shadow
   colour the rest of this section already casts in, it is what makes the
   object read as BOUND rather than as another rectangle, and losing it loses
   the only thing that says "magazine" about a closed cover. That is the test
   the no-coloured-strip rule actually asks: is the strip carrying meaning, or
   standing in for it. */
.ps-cover .ps-paper::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 9px;
  background: linear-gradient(90deg, rgba(92,61,46,0.22), rgba(92,61,46,0.02) 70%, transparent);
  border-radius: 1px 0 0 1px; z-index: 2; pointer-events: none;
}
.ps-masthead { display: flex; align-items: baseline; justify-content: space-between; gap: 0.6rem; padding: 0.1rem 0.15rem 0.5rem 0.3rem; }
.ps-masthead b { font-family: 'Dancing Script', cursive; font-weight: 600; font-size: 1.45rem; line-height: 1; color: var(--brown); }
.ps-masthead i {
  font-style: normal; font-family: 'Inter', sans-serif; font-size: 0.55rem;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--brown2);
}
.ps-cover .ps-frame { aspect-ratio: 2 / 3; }
.ps-coverline {
  font-family: 'Dancing Script', cursive; font-size: 1.06rem; line-height: 1.25;
  color: var(--brown2); text-align: center; padding: 0.5rem 0.4rem 0.6rem;
}

/* ── the open spread ───────────────────────────────────── */
.ps-spread .ps-paper { display: grid; grid-template-columns: 1fr 1fr; border-radius: 3px; }
.ps-page { position: relative; z-index: 1; min-width: 0; }
/* The gutter is the two inner edges falling away from each other. */
.ps-page-l { padding: 11px 6px 11px 11px; box-shadow: inset -24px 0 26px -24px rgba(92,61,46,0.45); }
.ps-page-r { padding: 11px 11px 11px 6px; box-shadow: inset  24px 0 26px -24px rgba(92,61,46,0.45); display: flex; flex-direction: column; justify-content: center; gap: 0.85rem; }
.ps-page-l .ps-frame { height: 100%; min-height: 0; }
.ps-page-l .ps-frame img { object-fit: contain; }
/* The vine is printed down the outer margin, the way a zine prints its border. */
.ps-orn-vine { right: 4px; top: 6%; width: 30%; opacity: 0.3; }
.ps-page-r > *:not(.ps-orn) { position: relative; z-index: 1; }

.ps-badge {
  display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0.3rem 0.8rem; border-radius: 3px;
  background: rgba(200,168,75,0.1); border: 1px solid rgba(200,168,75,0.4);
  font-family: 'Inter', sans-serif; font-size: 0.64rem; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--brown); width: fit-content;
}
.ps-title {
  font-family: 'Cormorant Garamond', serif; font-weight: 300;
  font-size: clamp(1.6rem, 2.4vw, 2.15rem); color: var(--brown); line-height: 1.12;
  margin: 0;
}
.ps-body {
  font-family: 'Inter', sans-serif; font-weight: 300; font-size: 0.82rem;
  color: var(--brown2); line-height: 1.72; margin: 0;
}
.ps-folio {
  font-family: 'Inter', sans-serif; font-size: 0.55rem; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--brown2); margin-top: 0.4rem;
}

/* ── the loose sheet ───────────────────────────────────── */
.ps-sheet .ps-paper { padding: 11px 11px 0; border-radius: 2px; }
/* One sheet lifted off the pile catches the light across itself. */
.ps-sheet .ps-paper::after {
  content: ''; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background: linear-gradient(101deg, rgba(255,255,255,0) 38%, rgba(255,255,255,0.36) 60%, rgba(92,61,46,0.05) 76%, rgba(255,255,255,0) 92%);
}
.ps-sheet .ps-frame { aspect-ratio: 4 / 3; }
.ps-caption {
  font-family: 'Dancing Script', cursive; font-size: 1.04rem; line-height: 1.25;
  color: var(--brown2); text-align: center; padding: 0.45rem 0.3rem 0.55rem;
}

/* ── the plate, mounted on a back page ─────────────────── */
.ps-plate .ps-paper {
  padding: 15px 15px 12px; border-radius: 2px; background: var(--parch);
  background-image: radial-gradient(rgba(139,158,122,0.22) 1.1px, transparent 1.2px);
  background-size: 10px 10px;
}
/* A double rule around the plate, the way a zine mats a photograph. It is a
   ring, not an edge: a bar down one side is the thing this repo forbids. */
.ps-mat {
  display: block; position: relative; z-index: 1; padding: 11px; background: var(--card-bg);
  box-shadow:
    inset 0 0 0 1px rgba(139,158,122,0.45),
    inset 0 0 0 4px var(--card-bg),
    inset 0 0 0 5px rgba(139,158,122,0.2);
}
.ps-plate .ps-frame { aspect-ratio: 2 / 3; }
.ps-orn-leaf { left: 50%; bottom: 6px; width: 46%; transform: translateX(-50%); opacity: 0.5; }
/* The one caption not sitting on clean stock. Dotted paper takes --brown2 to
   4.62:1, close enough to the 4.5 floor that a printer's dot decides it, so
   this one is set in --brown at 8.57:1 instead. */
.ps-plate .ps-caption { padding-bottom: 1.5rem; color: var(--brown); }

/* ── the burst, which carries a number and not an ornament ────────── */
.ps-burst {
  justify-self: start; width: 116px; aspect-ratio: 1;
  display: grid; place-content: center; text-align: center;
  background: color-mix(in srgb, var(--sage) 68%, var(--cream));
  clip-path: polygon(50.0% 0.0%, 57.2% 13.7%, 69.1% 3.8%, 70.6% 19.2%, 85.4% 14.6%, 80.8% 29.4%, 96.2% 30.9%, 86.3% 42.8%, 100.0% 50.0%, 86.3% 57.2%, 96.2% 69.1%, 80.8% 70.6%, 85.4% 85.4%, 70.6% 80.8%, 69.1% 96.2%, 57.2% 86.3%, 50.0% 100.0%, 42.8% 86.3%, 30.9% 96.2%, 29.4% 80.8%, 14.6% 85.4%, 19.2% 70.6%, 3.8% 69.1%, 13.7% 57.2%, 0.0% 50.0%, 13.7% 42.8%, 3.8% 30.9%, 19.2% 29.4%, 14.6% 14.6%, 29.4% 19.2%, 30.9% 3.8%, 42.8% 13.7%);
  transform: rotate(-9deg);
  filter: drop-shadow(3px 8px 16px rgba(92,61,46,0.16));
}
.ps-burst b {
  display: block; font-family: 'Cormorant Garamond', serif; font-weight: 600;
  font-size: clamp(1.7rem, 2.6vw, 2.4rem); line-height: 1; color: var(--brown);
}
.ps-burst span {
  display: block; font-family: 'Inter', sans-serif; font-size: 0.6rem;
  letter-spacing: 0.15em; text-transform: uppercase; color: var(--brown);
  margin-top: 0.28rem;
}

/* ── the maker's tag ──────────────────────────────────────────────── */
.ps-tag {
  justify-self: end; width: 116px; aspect-ratio: 1; border-radius: 50%;
  background: var(--pink); display: grid; place-content: center;
  text-align: center; padding: 0.4rem;
  font-family: 'Dancing Script', cursive; font-size: 1.12rem; line-height: 1.15;
  color: var(--brown); transform: rotate(6deg);
  box-shadow: 3px 8px 20px rgba(92,61,46,0.16);
}

.ps-foot { display: flex; justify-content: center; margin-top: 2.6rem; position: relative; z-index: 1; }
.ps-cta { background: var(--parch); color: var(--brown); border: 1px solid rgba(139,158,122,0.75); }

/* ── the desk, once there is room for one ─────────────────────────── */
@media (min-width: 901px) {
  .ps-scatter {
    gap: 0; max-width: none; margin: 0;
    grid-template-columns: repeat(12, 1fr);
    grid-template-rows: repeat(12, 1fr);
    aspect-ratio: 1200 / 1240;
  }
  .ps-piece { align-self: start; }
  /* The cover overlaps the spread, but it stops short of the poster's title.
     An overlap that eats a word is the same bug as a caption behind a print:
     the arrangement has to be arranged around the reading, not the shapes. */
  .ps-spread { grid-area: 1 / 5 / 8 / 13;   --tilt: 1.8deg;  --lean: -5deg; z-index: 3; }
  /* Pushed to the right of its own area: a tilted cover's bounding box reaches
     further left than the grid line does, and at 1200, where the content
     column is only 38px off the window, the left corner was 5px from the edge.
     That reads as an accident rather than as a bleed. */
  .ps-cover  { grid-area: 3 / 1 / 11 / 5;   --tilt: -6.5deg; --lean:  8deg; z-index: 5;
               width: 94%; justify-self: end; }
  /* The loose sheet slid UNDER the bound things, which is where a loose sheet
     ends up on a real table, and it is the only stacking order that leaves
     the cover's own caption readable. */
  .ps-sheet  { grid-area: 8 / 3 / 13 / 9;   --tilt: -2.4deg; --lean:  7deg; z-index: 2; }
  .ps-plate  { grid-area: 7 / 9 / 13 / 13;  --tilt: 5deg;    --lean: -7deg; z-index: 4;
               width: 88%; justify-self: end; }
  .ps-burst  { grid-area: 1 / 1 / 4 / 4;    z-index: 8; width: 76%; }
  /* Bottom-left is the one corner of this desk nothing printed reaches, and a
     maker's tag belongs on the table rather than on somebody's page. */
  .ps-tag    { grid-area: 10 / 1 / 13 / 3;  align-self: end; z-index: 8; width: 96%; }
}

/* ── two columns, no stage ────────────────────────────────────────── */
@media (min-width: 601px) and (max-width: 900px) {
  .ps-scatter {
    max-width: none; grid-template-columns: repeat(2, 1fr);
    gap: 1.6rem 1.3rem; align-items: start;
  }
  .ps-burst  { grid-area: 1 / 1; }
  .ps-tag    { grid-area: 1 / 2; align-self: center; }
  .ps-spread { grid-area: 2 / 1 / 3 / 3; }
  .ps-cover  { grid-area: 3 / 1; }
  .ps-plate  { grid-area: 3 / 2; }
  .ps-sheet  { grid-area: 4 / 1 / 5 / 3; }
}

/* ── one column: the spread unfolds ───────────────────────────────── */
@media (max-width: 900px) {
  .ps-spread  { --tilt: 1deg; }
  .ps-cover   { --tilt: -1.6deg; }
  .ps-sheet   { --tilt: 1.2deg; }
  .ps-plate   { --tilt: 1.6deg; }
  .ps-piece   { --lean: 0deg; }
  .ps-piece:hover { transform: perspective(1500px) translateY(-5px) scale(1.01); }
}
@media (max-width: 600px) {
  /* A spread 170px to a page is not a spread. It becomes one page above the
     other, and the gutter, which is only true of facing pages, goes away. */
  .ps-spread .ps-paper { grid-template-columns: 1fr; }
  .ps-page-l { padding: 11px 11px 0; box-shadow: none; }
  .ps-page-r { padding: 0.9rem 11px 14px; box-shadow: none; }
  .ps-page-l .ps-frame { height: auto; aspect-ratio: 2 / 3; }
  .ps-orn-vine { display: none; }
}

/* ── SEO ──────────────────────────────────────────────── */
#seo { background: var(--mauve); }
.seo-context { text-align: center; margin-top: 1.2rem; font-family: 'Dancing Script', cursive; font-size: 1.05rem; color: var(--brown2); }

/* Interactive hover layout */
.seo-showcase { display: flex; gap: 4rem; align-items: stretch; margin-top: 2.8rem; min-height: 360px; }

/* Left: brand list */
/* THE INDICATOR STAYS; THE TRACK IT RAN IN DOES NOT. The 2px strip down this list's left edge was
   a rail - a static decoration - and the ::before below is the thing that actually carries
   information: which brand is on screen. Losing the track costs nothing, because the rows already
   have their own hairlines, and it stops a state marker from being read as an ornament. */
.seo-names { flex: 0 0 220px; display: flex; flex-direction: column; justify-content: center; gap: 0; padding-left: 0; }
.seo-name-item {
  display: flex; align-items: center; gap: 1rem; padding: 1.2rem 1.4rem;
  cursor: pointer; position: relative; transition: background 0.2s;
  border-bottom: 1px solid rgba(139,99,85,0.09);
}
.seo-name-item:first-child { border-top: 1px solid rgba(139,99,85,0.09); }
.seo-name-item::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: var(--brown); transform: scaleY(0); transition: transform 0.25s;
}
.seo-name-item.active::before, .seo-name-item:hover::before { transform: scaleY(1); }
.seo-name-item.active, .seo-name-item:hover { background: rgba(255,255,255,0.45); }
.seo-name-num { font-family: 'Inter', sans-serif; font-size: 0.62rem; letter-spacing: 0.12em; color: var(--brown2); opacity: 0.6; min-width: 1.4rem; }
.seo-name-label { font-family: 'Cormorant Garamond', serif; font-size: 1.55rem; font-weight: 600; color: var(--brown); letter-spacing: 0.06em; transition: color 0.2s; }
.seo-name-item.active .seo-name-label, .seo-name-item:hover .seo-name-label { color: var(--brown2); }
.seo-name-arrow { margin-left: auto; font-size: 0.8rem; opacity: 0; transition: opacity 0.2s, transform 0.2s; }
.seo-name-item.active .seo-name-arrow, .seo-name-item:hover .seo-name-arrow { opacity: 1; transform: translateX(3px); }

/* Right: image reveal */
.seo-preview { flex: 1 1 0; position: relative; border-radius: 6px; overflow: hidden; background: rgba(255,255,255,0.3); box-shadow: 0 4px 32px rgba(92,61,46,0.1); }
.seo-slide { position: absolute; inset: 0; opacity: 0; transition: opacity 0.45s ease; }
.seo-slide.active { opacity: 1; }
.seo-slide img { width: 100%; height: 100%; object-fit: cover; object-position: top; display: block; }
.seo-slide-label {
  position: absolute; bottom: 1.2rem; left: 1.2rem;
  background: rgba(237,232,220,0.9); backdrop-filter: blur(6px);
  padding: 0.4rem 1rem; border-radius: 100px;
  font-family: 'Inter', sans-serif; font-size: 0.68rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--brown); font-weight: 400;
}

/* ── About ────────────────────────────────────────────── */
#about { background: var(--cream); }
.about-grid { display: grid; grid-template-columns: 1fr 1.4fr; gap: 5rem; align-items: center; }
.about-portrait { position: relative; overflow: visible; }
.about-portrait-accent { position: absolute; top: -20px; left: -20px; width: 80px; height: 80px; border: 2px solid var(--pink); border-radius: 50%; opacity: 0.4; pointer-events: none; }
.about-portrait-frame { position: relative; overflow: visible; aspect-ratio: 551 / 666; }
/* "hãy làm cho ... cánh có thể chuyển động" - her own fairy-wing photo, wings
   fluttering, an H3 i2va animation off that still (locked camera, only the wings
   move). Boomeranged the same way as the hero border for a clean loop point.
   "khung này y hệt" -- her own reference, an ornate oval frame, is a real
   imported PNG rather than a CSS-drawn line: a hairline border can't reproduce
   carved bow corners. The container's own ratio is the frame PNG's native
   pixel ratio (1102:1332, reduced), so the frame fills it undistorted -- no
   guessed inset percentage standing in for the actual asset.
   "fitted into the frame like a mirror... wings clipped into the circle" --
   the oval isn't eyeballed either: connected-component labelling on the PNG's
   own alpha (the enclosed transparent region, distinguished from the
   background transparency by NOT touching the canvas border) gave the hole's
   true bounding ellipse -- center 50.05%/50.19%, radii 35.25%/38.63% of the
   canvas. `clip-path` uses those numbers directly, so what shows through is
   exactly the hole the asset actually has, not an approximation of it.
   The ellipse sits on its own wrapper rather than on the video, so the clip
   stays pinned to the container at those fixed percentages no matter how the
   video inside is sized -- shrinking the video to pull more of the wingspan
   into frame doesn't also shrink the hole it's being viewed through. */
.about-portrait-clip {
  position: absolute; inset: 0;
  clip-path: ellipse(35.25% 38.63% at 50.05% 50.19%);
}
.about-portrait-clip video {
  position: absolute; top: 50%; left: 50%; height: 80%; width: auto;
  aspect-ratio: 1088 / 928; transform: translate(-50%, -50%); object-fit: cover;
  filter: sepia(0.08) saturate(1.12);
}
.about-portrait-frame img {
  position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none;
  filter: drop-shadow(6px 10px 26px rgba(92,61,46,0.28));
}
.about-bio { font-family: 'Inter', sans-serif; font-weight: 300; font-size: 0.95rem; color: var(--brown); line-height: 1.85; margin-bottom: 2rem; }
.about-bio strong { font-weight: 400; }
.about-tags { display: flex; flex-wrap: wrap; gap: 0.6rem; margin-bottom: 2rem; }
.about-tag { padding: 0.35rem 0.9rem; border-radius: 100px; border: 1px solid rgba(92,61,46,0.2); font-family: 'Inter', sans-serif; font-size: 0.7rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--brown2); }
.j1-notice { display: inline-flex; align-items: center; gap: 0.6rem; padding: 0.6rem 1.2rem; background: rgba(200,168,75,0.1); border: 1px solid rgba(200,168,75,0.4); border-radius: 4px; font-family: 'Inter', sans-serif; font-size: 0.72rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--brown); font-weight: 400; }
.j1-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--gold); flex-shrink: 0; }

/* ── Contact ──────────────────────────────────────────── */
#contact { background: var(--dark); position: relative; overflow: hidden; }
.contact-bg-text { position: absolute; bottom: -4rem; right: -2rem; font-family: 'Cormorant Garamond', serif; font-size: clamp(8rem,20vw,16rem); font-weight: 300; color: rgba(237,232,220,0.03); pointer-events: none; white-space: nowrap; line-height: 1; }
.contact-inner { max-width: 800px; margin: 0 auto; padding: 7rem 2.4rem; text-align: center; position: relative; z-index: 1; }
.contact-heading { font-family: 'Cormorant Garamond', serif; font-weight: 300; font-size: clamp(2.8rem,6vw,5rem); color: var(--cream); line-height: 1.1; margin-bottom: 1.6rem; }
.contact-heading em { font-style: italic; color: var(--pink-d); }
.contact-sub { font-family: 'Dancing Script', cursive; font-size: 1.1rem; color: var(--sage); margin-bottom: 3rem; }
.contact-links { display: flex; flex-direction: column; align-items: center; gap: 1.2rem; margin-bottom: 3.5rem; }
.contact-link { display: inline-flex; align-items: center; min-height: 24px; font-family: 'Inter', sans-serif; font-weight: 300; font-size: 0.85rem; color: rgba(237,232,220,0.65); text-decoration: none; letter-spacing: 0.06em; transition: color 0.2s; }
.contact-link:hover { color: var(--cream); }
.contact-socials { display: flex; justify-content: center; gap: 1.2rem; flex-wrap: wrap; margin-bottom: 3rem; }
.social-chip { padding: 0.45rem 1rem; border-radius: 100px; border: 1px solid rgba(237,232,220,0.15); font-family: 'Inter', sans-serif; font-size: 0.72rem; letter-spacing: 0.08em; color: rgba(237,232,220,0.55); text-decoration: none; transition: border-color 0.2s, color 0.2s; }
.social-chip:hover { border-color: var(--pink-d); color: var(--cream); }
.footer-line { font-family: 'Inter', sans-serif; font-size: 0.65rem; letter-spacing: 0.2em; text-transform: uppercase; color: rgba(237,232,220,0.22); }
