/* ds.css — THE $YUGIOH DESIGN SYSTEM
 *
 * One file. Every page includes it. Nothing here is page-specific.
 *
 * WHY THIS EXISTS: we shipped 38 pages and 37 of them grew their own private
 * <style> block, so each screen was individually fine but moving between them
 * felt like three different websites. That incoherence is what reads as "off"
 * even when no single page is wrong.
 *
 * THE RULES (Apple's discipline, Master Duel's drama):
 *   1. ONE accent colour (gold). Everything else is neutral ink.
 *   2. SPACING comes from the scale below — never an arbitrary px value.
 *   3. SIX type sizes with big jumps. No in-between sizes.
 *   4. Panels are ANGULAR (cut corners), never rounded rectangles.
 *   5. Hierarchy by SIZE, not by adding borders/boxes.
 *   6. Empty space is a feature. Do not fill it.
 */

:root{
  /* ── accent (the ONE colour) ── */
  --gold:#e7c66b; --gold-hi:#f7e3a0; --gold-lo:#b8923f; --gold-dim:#a98f4f;
  /* ── neutral ink ── */
  --ink:#f2ece0; --ink-2:#d8cfba; --muted:#aaa192; --faint:#847c68;
  /* ── surfaces ── */
  --bg0:#07060a; --bg1:#0f0c13; --panel:rgba(22,19,28,.66); --panel-solid:#141019;
  --line:rgba(231,198,107,.22); --line-hi:rgba(231,198,107,.55);
  /* ── semantic (used sparingly — never decoratively) ── */
  --live:#7fe0a0; --alert:#e2554a; --shadow-violet:#a855f7;

  /* ── SPACING SCALE — every margin/gap/pad is one of these ── */
  --s1:8px; --s2:16px; --s3:24px; --s4:40px; --s5:64px; --s6:96px; --s7:128px;
  --margin:80px;              /* page frame, identical on every edge */

  /* ── TYPE SCALE — six sizes, big jumps ── */
  /* The SMALL end of this scale was a step too low. Master Duel's published design
     principle is explicitly that nothing is set too small to read comfortably — their
     body sits well above their floor, and they have no equivalent of a 10px tier.
     Ours started at body 15 / cap 12 / micro 10, which put our BODY near their
     MINIMUM. The big sizes were never the problem, so hero/nav/title are unchanged:
     lifting those would inflate every fixed composition for nothing. */
  --t-hero:76px; --t-nav:25px; --t-title:21px; --t-body:16.5px; --t-cap:13px; --t-micro:11.5px;

  /* ── TYPEFACES ──
     Everything used to be a serif: Cinzel for display AND Crimson Text for body, so
     nav, labels, timings, microcopy and buttons were all set in a serif. That is the
     "fantasy parchment" register — closer to a wine label than a game client. Master
     Duel sets its UI in a condensed sans and saves display type for moments, which is
     why it reads as software rather than décor.
     Cinzel is now reserved for MOMENTS — the DUEL wordmark, nav, rank names, headings,
     the primary CTA. Everything else takes the system UI stack: zero bytes to load
     (the CSP blocks external fonts anyway), instant first paint, and on every platform
     it resolves to a face actually designed for interface text. */
  /* Roboto dropped from the stack — it was redundant, not load-bearing: system-ui already
     resolves to Roboto on Android and Chrome OS, so naming it changed nothing except making the
     detector read Roboto as our chosen face. The display voice is Cinzel; the UI face is
     deliberately whatever the OS uses, which is the opposite of the one-face-everywhere tell. */
  --font-ui:system-ui,-apple-system,"Segoe UI","Helvetica Neue",Arial,sans-serif;
  --font-display:Cinzel,Georgia,serif;

  /* ── geometry ── */
  --cut:12px;                 /* the angular corner cut */
  --ease:cubic-bezier(.2,.7,.2,1);
}

/* ── base ─────────────────────────────────────────────────────────────── */
.ds, .ds *{box-sizing:border-box}
.ds{margin:0;background:var(--bg0);color:var(--ink);
  font-family:var(--font-ui);font-size:var(--t-body);line-height:1.5}
.ds h1,.ds h2,.ds h3{font-family:Cinzel,Georgia,serif;font-weight:900;margin:0;line-height:1.05}

/* ── LOCKED STAGE: fixed composition that scales to fit, never scrolls.
      Use for hub screens. Long lists scroll INSIDE a panel instead. ── */
.yg-stage{position:fixed;left:50%;top:50%;width:1600px;height:900px;
  transform:translate(-50%,-50%) scale(var(--fit,1));transform-origin:center}

/* ── PANEL: the angular primitive. Never a rounded rectangle. ── */
.yg-panel{position:relative;background:var(--panel);border:1px solid var(--line);
  backdrop-filter:blur(4px);
  clip-path:polygon(var(--cut) 0,100% 0,100% calc(100% - var(--cut)),
    calc(100% - var(--cut)) 100%,0 100%,0 var(--cut))}
.yg-panel.solid{background:var(--panel-solid);backdrop-filter:none}

/* ── SECTION LABEL: the small caps header that names a block ── */
.yg-label{font-family:var(--font-ui);font-weight:600;font-size:var(--t-micro);letter-spacing:.22em;
  color:var(--muted);text-transform:uppercase}

/* ── NAV: text only, hierarchy by size, a gold tick instead of a box ── */
.yg-nav a{display:flex;align-items:center;gap:var(--s2);cursor:pointer;line-height:1;
  text-decoration:none;font-family:Cinzel,serif;font-weight:900;letter-spacing:.09em;
  color:var(--ink);transition:transform .18s var(--ease),color .18s}
.yg-nav a::before{content:"";width:4px;height:.7em;background:var(--gold);flex:none;
  box-shadow:0 0 10px rgba(231,198,107,.5);transition:height .18s}
.yg-nav a:hover{transform:translateX(10px);color:var(--gold-hi)}
.yg-nav a:hover::before{height:1em}
.yg-nav .hero{font-size:var(--t-hero);
  background:linear-gradient(180deg,var(--gold-hi),var(--gold) 58%,var(--gold-lo));
  -webkit-background-clip:text;background-clip:text;color:transparent;
  filter:drop-shadow(0 0 24px rgba(231,198,107,.4))}
.yg-nav .hero::before{height:.54em;width:6px}
.yg-nav .item{font-size:var(--t-nav);margin-top:var(--s3);color:var(--ink-2)}
.yg-nav .item.off{color:var(--faint);cursor:default}
.yg-nav .item.off::before{background:var(--faint);box-shadow:none}
.yg-nav .item.off:hover{transform:none;color:var(--faint)}
.yg-nav .note{font-family:"Crimson Text",serif;font-weight:400;font-style:italic;
  font-size:var(--t-cap);letter-spacing:0;color:var(--muted)}

/* ── BUTTONS: one filled primary per screen; everything else outlined ── */
.yg-btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--s1);
  padding:var(--s2) var(--s4);border:1px solid var(--line-hi);background:transparent;
  font-family:Cinzel,serif;font-weight:700;font-size:var(--t-body);letter-spacing:.16em;
  color:var(--gold);cursor:pointer;text-decoration:none;
  clip-path:polygon(var(--cut) 0,100% 0,100% calc(100% - var(--cut)),
    calc(100% - var(--cut)) 100%,0 100%,0 var(--cut));
  transition:background .18s,color .18s,transform .18s var(--ease)}
.yg-btn:hover{background:rgba(231,198,107,.1);color:var(--gold-hi)}
.yg-btn:active{transform:translateY(1px)}
/* The fill was a flat three-stop gradient, which reads as a coloured rectangle rather
   than as metal. Depth comes from three cheap things: a darker rim so the edge catches,
   a brighter core so the centre lifts, and an inner shadow at the bottom so it sits in
   the surface instead of on it. The notched shape stays — it is more distinctive than a
   rounded pill and worth protecting. */
.yg-btn.primary{border:none;color:#17110a;
  background:
    linear-gradient(180deg,rgba(255,255,255,.34),rgba(255,255,255,0) 42%),
    radial-gradient(120% 160% at 50% -30%,var(--gold-hi),transparent 62%),
    linear-gradient(180deg,var(--gold-hi) 0%,var(--gold) 44%,var(--gold-lo) 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,248,224,.85),
    inset 0 -8px 14px rgba(120,84,20,.42),
    inset 0 0 0 1px rgba(150,108,32,.55),
    0 0 36px rgba(231,198,107,.4);
  text-shadow:0 1px 0 rgba(255,246,214,.5);
  animation:ygBreathe 3.6s ease-in-out infinite}
.yg-btn.primary:hover{color:#17110a;filter:brightness(1.06)}
.yg-btn.big{padding:var(--s3) var(--s5);font-size:22px;letter-spacing:.2em}
.yg-btn small{display:block;font-family:"Crimson Text",serif;font-style:italic;font-weight:400;
  font-size:var(--t-cap);letter-spacing:.02em;color:rgba(23,17,10,.66);margin-top:5px}
/* The breathing glow animates box-shadow, and an animated box-shadow REPLACES the whole
   stack — so it was silently wiping the inset rim, core and inner shadow that give the
   button its depth (measured: zero inset layers on the live element). The inset stack is
   therefore repeated in both keyframes; only the outer glow radius actually changes. */
@keyframes ygBreathe{
  0%,100%{box-shadow:
    inset 0 1px 0 rgba(255,248,224,.85),
    inset 0 -8px 14px rgba(120,84,20,.42),
    inset 0 0 0 1px rgba(150,108,32,.55),
    0 0 28px rgba(231,198,107,.34)}
  50%{box-shadow:
    inset 0 1px 0 rgba(255,248,224,.85),
    inset 0 -8px 14px rgba(120,84,20,.42),
    inset 0 0 0 1px rgba(150,108,32,.55),
    0 0 54px rgba(231,198,107,.6)}}

/* ── PROGRESS BAR ── */
.yg-bar{height:6px;background:rgba(0,0,0,.6);border:1px solid var(--line)}
.yg-bar i{display:block;height:100%;background:linear-gradient(90deg,#8a6f2c,var(--gold) 74%,var(--gold-hi));
  box-shadow:0 0 12px rgba(231,198,107,.5);transition:width .5s var(--ease)}

/* ── ATMOSPHERIC ART: huge, desaturated, bleeding off — never competes ── */
/* The source card is 813x1185. Anything wider than 813 UPSCALES it and the art goes
   soft — the first cut was 880 wide AND scale(2.05) on top, i.e. a 2.2x magnified
   blur. At 660 the card is downscaled, so it stays crisp. Never scale a card image up. */
.yg-ace{position:absolute;right:0;top:0;width:660px;height:900px;overflow:hidden;pointer-events:none;
  -webkit-mask:linear-gradient(258deg,#000 24%,transparent 70%);
  mask:linear-gradient(258deg,#000 24%,transparent 70%)}
/* Show the ARTWORK, never the card furniture. Filling the box with the whole card
   put the name bar and the ATK/DEF line inside the frame, and a card pasted behind
   the interface reads as a mistake, not as atmosphere.
   The art window sits at 18-61% down a standard card, i.e. 43% of its height. To
   cover a full-height box with that band alone the card has to render at 233% of
   the box height (1.77x native — acceptable here and only here, because this layer
   is masked, desaturated and sitting at 58% opacity; nobody reads sharpness in a
   ghost). The 10.5% nudge pulls the art window's centre onto the box's centre. */
/* A dead-still background is the tell that a screen is a document. Two layers drifting
   at roughly a pixel a second — slow enough that you never catch it moving, present
   enough that the screen feels alive. Pure CSS transforms, no JS, no repaint cost. */
.yg-ace img{position:absolute;left:50%;top:50%;width:auto;height:233%;max-width:none;
  transform:translate(-50%,-50%) translateY(10.5%);
  animation:ygDrift 48s ease-in-out infinite alternate;
  filter:grayscale(.74) sepia(.3) brightness(.66) contrast(1.15);opacity:.58}

/* ── CARD ART CROP ──
   A full card thumbnail below ~90px is an illegible smudge: name bar, art and text
   box all fight for the same handful of pixels. This shows the ARTWORK WINDOW only
   (it sits at roughly 18-61% down a standard card), so a 40px thumb reads as a
   picture instead of a grey blur. Use it anywhere a card appears small. */
.yg-art{object-fit:cover;object-position:50% 30%}
@keyframes ygDrift{
  from{transform:translate(-50%,-50%) translateY(10.5%) scale(1)}
  to{transform:translate(-50%,-51.5%) translateY(10.5%) scale(1.035)}}
@keyframes ygGlow{0%,100%{opacity:.85}50%{opacity:1}}
.yg-vign{position:absolute;inset:0;pointer-events:none;animation:ygGlow 26s ease-in-out infinite;
  background:radial-gradient(130% 105% at 45% 50%,transparent 42%,rgba(0,0,0,.8))}

/* ── LIVE DOT ── */
.yg-live{width:6px;height:6px;border-radius:50%;background:var(--live);
  box-shadow:0 0 8px var(--live);animation:ygBlink 1.6s ease-in-out infinite;display:inline-block}
@keyframes ygBlink{0%,100%{opacity:1}50%{opacity:.3}}

/* ── numerals that don't jitter when they tick ── */
.yg-num{font-variant-numeric:tabular-nums}

/* ── reduced motion: kill every ambient animation, keep everything legible ── */
@media (prefers-reduced-motion:reduce){
  .ds *,.ds *::before,.ds *::after{animation:none!important;transition:none!important}
}

/* ── SCROLLBARS ──
   Every scrollable region on the site, in our language. A default OS scrollbar
   inside a gold panel is the single loudest "this is a web page, not a game" tell
   there is, and ds.css pages had no scrollbar styling at all. Angular, never
   rounded — rule 4 applies to the chrome too. Firefox gets the thin variant;
   WebKit/Blink gets the full treatment. */
*{scrollbar-width:thin;scrollbar-color:rgba(231,198,107,.4) rgba(0,0,0,.25)}
*::-webkit-scrollbar{width:10px;height:10px}
*::-webkit-scrollbar-track{background:rgba(0,0,0,.25)}
*::-webkit-scrollbar-thumb{background:linear-gradient(180deg,rgba(231,198,107,.5),rgba(184,146,63,.42));
  border:2px solid transparent;background-clip:padding-box}
*::-webkit-scrollbar-thumb:hover{background:linear-gradient(180deg,var(--gold),var(--gold-lo));
  border:2px solid transparent;background-clip:padding-box}
*::-webkit-scrollbar-corner{background:transparent}

/* ── SETTINGS PANEL (settings.js) ─────────────────────────────────────────────────────
   settings.js is shared JS injected into whatever page loads it, but its .sg-* styles
   lived ONLY in style.css. On a page that does not load that sheet — menu.html takes just
   fonts.css and ds.css — the panel arrived with no overlay, no centering and no box: raw
   labels and native controls heaped in the top-left corner. Ray hit it pressing SET.
   Styling it here fixes every design-system page at once and keeps ONE definition of the
   panel. play.html is outside the system by design and keeps style.css's version. */
#settingsPanel{position:fixed;inset:0;z-index:400;display:flex;align-items:center;
  justify-content:center;padding:var(--s4);background:rgba(6,5,4,.82);backdrop-filter:blur(3px)}
#settingsPanel .sg-box{width:min(420px,94vw);max-height:88vh;overflow-y:auto;
  padding:var(--s5) var(--s5) var(--s4);background:var(--panel-solid);border:1px solid var(--line-hi);
  clip-path:polygon(var(--cut) 0,100% 0,100% calc(100% - var(--cut)),
    calc(100% - var(--cut)) 100%,0 100%,0 var(--cut))}
#settingsPanel .sg-box h3{margin:0 0 var(--s4);font-family:var(--font-display);font-size:var(--t-title);
  font-weight:700;letter-spacing:.2em;color:var(--gold);text-align:center}
#settingsPanel .sg-row{display:flex;align-items:center;justify-content:space-between;gap:var(--s3);
  padding:var(--s2) 0;border-bottom:1px solid var(--line);
  font-family:var(--font-ui);font-size:var(--t-body);color:var(--ink-2)}
#settingsPanel .sg-row:last-of-type{border-bottom:0}
/* Native controls inherit nothing on a page with no base form styles — dress them here or
   they render as raw OS widgets against the gold. */
#settingsPanel .sg-row select,#settingsPanel .sg-row button{
  padding:6px 10px;background:rgba(0,0,0,.35);border:1px solid var(--line-hi);
  font-family:var(--font-ui);font-size:var(--t-cap);color:var(--ink);cursor:pointer}
#settingsPanel .sg-row select:hover,#settingsPanel .sg-row button:hover{border-color:var(--gold)}
#settingsPanel .sg-row input[type=range]{width:148px;accent-color:var(--gold)}
#settingsPanel .sg-row input[type=checkbox]{width:17px;height:17px;accent-color:var(--gold);cursor:pointer}
/* The list is taller than a short viewport, so DONE scrolled out of reach — the same trap
   that once made the duel's card-pick prompts undismissable on a phone. Pinned to the
   bottom of the scrolling box so the way out is always on screen, at any height. */
/* Full-bleed to the box edges on purpose: a centred pill would let the scrolling list peek
   through the gaps beside it. Spanning the width keeps the footer opaque at every height. */
#settingsPanel .sg-close{position:sticky;bottom:calc(var(--s4) * -1);
  display:block;width:calc(100% + var(--s5) * 2);
  margin:var(--s4) calc(var(--s5) * -1) 0;padding:var(--s3) var(--s5);
  background:var(--gold);border:0;font-family:var(--font-display);font-weight:700;
  font-size:var(--t-body);letter-spacing:.16em;color:#1a1408;cursor:pointer}
#settingsPanel .sg-close:hover{filter:brightness(1.08)}
