/* =====================================================================
   GoDartsPro : Dedication
   /wp-content/themes/dart/assets/css/gdp-game-dedication.css

   Loaded AFTER gdp-game.css. Everything shared lives there; this file is
   only what Dedication arranges differently.

   Two rules for keeping it that way:

     Rules start here and move UP to gdp-game.css on their SECOND use, not
     in anticipation of one. Guessing what will be shared is how a shared
     file fills with things nobody reuses.

     Never redeclare a --gdp- token here. If a game needs different
     ground, that is a class on the wrapper in the shared file, not a fork
     of the palette.

   Same specificity as gdp-game.css and loaded later, so later wins and
   nothing here needs !important.
   ===================================================================== */


/* ---------- the overlay, in normal flow ----------
   The shared app JS opens this panel with slideToggle():

       $(".app-stats-container").slideToggle();

   which animates the container's CONTENT height. In -01 the panel is
   position:absolute inset:0 inside .gdp-wrap, which has a height of its
   own to fill. Dropped into a slide-toggled container, every child would
   be out of flow, the content height would be zero, and the panel would
   open to nothing.

   So Dedication puts it back in normal flow. The panel keeps its own
   opaque ground, which is what stops the setup screen showing through -
   the old .app-stats-area was rgba(0,0,0,0.9) and the dartboard graphic
   and the instructions read straight through the results table.

   Not a candidate for promotion: -01's absolute version is right for a
   panel that covers a game board. This is right for one that slides.
   ------------------------------------------------------------------- */
/* The .gdp wrapper carries the dark ground for the whole overlay, and it
   is a square block sitting inside .container-main-graphic, whose amber
   border is rounded. Without a radius of its own its corners paint over
   the inside of that curve and the frame reads as clipped the moment the
   panel opens.

   overflow:hidden as well, so the panel inside cannot poke back out
   through the corners it is now rounded to fit. */
.app-stats-container .gdp{
  border-radius:20px;
  overflow:hidden;
}

/* The panel is only as tall as its content - around 780px inside a 900px
   frame - so the game screen showed through underneath it: "Play another
   round?" visible but not clickable, because the overlay was on top of it
   without covering it.

   Filling the frame from the frame itself rather than stretching the
   panel. .app-stats-container is slide-toggled and its height rules are
   in the shared theme CSS, so anything that depends on knowing them is
   fragile; this needs to know nothing about it. The ground is painted
   across the whole of .container-main-graphic, inside its radius, and the
   panel sits above. */
/* Above the "Your stats" tab, which sits at z-index 1210 in the shared
   file. The tab is what opened the panel and the panel has its own close
   button, so leaving it visible on top only offers a second control that
   does the same job - and it sat over the panel's own corner. Both the
   ground and the panel clear it. */
.container-main-graphic.is-stats-open:before{
  content:"";
  position:absolute;
  inset:0;
  background:var(--gdp-bg);
  border-radius:20px;
  z-index:1290;
  pointer-events:none;
}
.container-main-graphic.is-stats-open .app-stats-container{
  position:relative;
  z-index:1300;
}

/* The class="gdp" wrapper sits INSIDE .app-stats-container, never on it.
   .gdp declares display:flow-root, which is the same specificity as the
   theme's .app-stats-container{display:none} and loads later - putting the
   two on one element forces the panel open on every page load and the
   player has to close it before they can start a game. */
.gdp .gdp-stats{
  position:static;
  display:block;
  border-radius:0;
  overflow:visible;
}

/* No scrim: there is nothing behind this panel to dim once it is opaque
   and in flow, and a fixed-size dark layer in the document would push the
   slide animation around. */
.gdp .gdp-stats-scrim{display:none;}

.gdp .gdp-stats-panel{
  position:static;
  transform:none;
  opacity:1;
  border-radius:var(--gdp-radius);
  /* No border. -01's panel floats over the game and needs its own edge;
     this one sits inside .container-main-graphic, which already draws one,
     and two concentric outlines a few pixels apart read as a mistake. */
}

/* The frame this panel sits in is .container-main-graphic, min-height:900px
   inline on the template. The shared CSS takes .app-stats-container out of
   flow, so the frame does NOT grow to follow a tall panel - the content
   simply runs past its border. Everything below is sized off this value,
   so if the inline min-height changes, change this too, and recompute the
   background seam stop in the template while you are there. */
.gdp{--ded-frame:900px;}

/* No scrollbar on the panel itself - only the session list scrolls. The
   shared .gdp-stats-body is a flex child with overflow-y:auto, which is
   right for a panel that fills a fixed-height game board; here it would
   put a second bar down the right of the whole stats view.

   Nothing needs a backstop now: with the filter in the header and the list
   capped at eight rows, the panel comes to roughly 810px inside a 900px
   frame. Height budget below - keep it honest if anything is added. */
.gdp .gdp-stats-body{overflow:visible;}

/* ---------- the session row ----------
   A practice session has different columns from a match: one target, one
   player, and two areas. The shared .gdp-session carries the look, the
   padding, the hover and the selected state; only the grid changes.

       dot | date | target and mode | darts | hits | area | best 95%
   ------------------------------------------------------------------- */
/* The column set is decided in JS from what the player has played - Close
   only if they have manual non-bull sessions, Bull and Outer only if they
   have bull ones - and handed here as --ded-cols so the header row and the
   session rows are laid out by one value and cannot drift apart. */
.gdp-session.is-practice{
  grid-template-columns:var(--ded-cols, 9px 62px minmax(0,1fr) 44px 44px 78px 78px);
}

/* Area is the column a player scans down looking for their best session,
   so it lines up on the decimal rather than centring. */
.gdp-session.is-practice .gdp-session-num{font-variant-numeric:tabular-nums;}
.gdp-session.is-practice .is-area{color:var(--gdp-ink);}
.gdp-session.is-practice .is-trimmed{color:var(--gdp-accent);}

/* Nothing tracked: an em dash in the line colour, so the row still reads
   as a session that happened rather than one that failed. */
.gdp-session.is-practice .is-none{color:var(--gdp-line);}

@media(max-width:760px){
  /* Folds the same way the match row does, via the shared
     .gdp-session-num[data-label] rule. Three columns on the first line,
     the numbers wrapping underneath with their labels attached. */
  .gdp-session.is-practice{
    grid-template-columns:9px 62px minmax(0,1fr);
  }
  /* The fold ignores --ded-cols: every number drops below the first line
     with its data-label attached, however many of them there are. */
}

/* Once the list is capped, the right column is what sets the panel height:
   board, plus its heading, mode chips, note line, advice block and the
   Performance Center link. Holding the board a little under the shared
   420px brings that column closer to eight session rows. */
.gdp .gdp-heat{max-width:390px;margin-left:auto;margin-right:auto;}

/* ---------- the board stack ----------
   .gdp-heat already positions the canvases; the SVG board underneath is
   what gives the stack its height, so it is the one element that must
   stay in normal flow. */
.gdp-heat .gdp-board{display:block;width:100%;height:auto;}

/* Two canvases here rather than one: the density field, and the hit area
   over it. Kept separate so switching between them is a class toggle
   instead of a repaint of both. */
.gdp-heat .js-heat-canvas{z-index:1;}
.gdp-heat .js-hitarea-canvas{z-index:2;}
.gdp-heat canvas.is-off{display:none;}

/* ---------- the panel header ----------
   Title left, target filter pushed right against the close button. Saves
   the ~70px the filter cost as its own row.

   Height budget for the panel, so the frame is never crossed again:

       header (title + filter on one line)      64
       figures, six across on one line          84
       body padding                             46
       tallest column - the board side,
         measured on screen, not calculated    580
                                               ----
                                                774   inside a 900 frame

   The session list is capped at 580 to match that column, so the two are
   level and either could set the height. If anything is added to the board
   side, measure it again and raise both together - and if the frame has to
   grow, recompute the background seam stop in the template with it.

   There is about 125px spare, so the frame could go back to min-height:800
   if the taller setup screen looks empty with the stats closed. That would
   put the seam stop back at 37.2%.
   ------------------------------------------------------------------- */
.gdp .gdp-stats-head{flex-wrap:wrap;gap:10px 14px;}
.gdp .gdp-stats-head h2{flex:0 0 auto;}
.gdp .gdp-stats-head .gdp-ded-targets{margin-left:auto;margin-bottom:0;}

@media(max-width:900px){
  /* Not enough room beside the title, so the filter takes its own line
     below it with the close button staying up on the first. */
  .gdp .gdp-stats-head h2{flex:1 1 auto;}
  .gdp .gdp-stats-head .gdp-ded-targets{
    order:3;
    flex:1 1 100%;
    margin-left:0;
  }
}

/* ---------- the target picker ----------
   Chips for the type, a select for the number, on one line. The select is
   the shared .gdp-select; only the alignment against the chips is new. */
.gdp-ded-targets{align-items:center;gap:5px;margin-bottom:18px;}
.gdp-ded-targets .gdp-select select{min-width:74px;text-align-last:center;}
.gdp-ded-targets .gdp-ded-or{
  font-family:var(--gdp-font);font-size:11px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--gdp-muted);padding:0 3px;
}

/* ---------- figures ----------
   All six on one line on a desktop. Two rows of three cost about 90px of
   height that the session list and the board both want, and none of the
   six matters more than the others - one row reads as a single set rather
   than two ranks.

   At 1170px the container leaves roughly 1100px inside its padding, so
   183px a box. The longest label, "30 DAYS MAX HITS", is about 130px at
   10px with .16em tracking, so it stays on one line. */
.gdp-figures.is-dedication{grid-template-columns:repeat(6,1fr);}

/* The shared figure size is set for two or three across. Six needs a lower
   ceiling or "33.59 cm2" runs into its own box edge. */
.gdp-figures.is-dedication .gdp-figure{padding:12px 8px;}
.gdp-figures.is-dedication .gdp-figure b{font-size:clamp(18px,2.1vw,26px);}
.gdp-figures.is-dedication .gdp-figure span{letter-spacing:.11em;}

@media(max-width:1100px){
  /* Six no longer fit without the labels wrapping. */
  .gdp-figures.is-dedication{grid-template-columns:repeat(3,1fr);}
}
@media(max-width:700px){
  .gdp-figures.is-dedication{grid-template-columns:repeat(2,1fr);}
}

/* The best area a player has ever managed on this target is a personal
   best, not a running total, so it carries the accent the way a checkout
   does in a match. */
.gdp-figure.is-best b{color:var(--gdp-accent);}

/* ---------- the session list scrolls, the panel does not ----------
   Up to 50 sessions come back. Left to grow, the list drives the height of
   the whole panel and the board ends up far down the page - and because
   .gdp-stats-grid is align-items:start, the right column does not follow
   it, so the panel is mostly empty space beside a very long list.

   Capping it keeps the two columns roughly level. 620px is the height of
   the right column at full width: the board is max-width 420 and square,
   plus its heading, mode chips, note, the advice block and the
   Performance Center link.

   Scrollbar copied from .gdp-stats-body rather than left to the platform,
   which draws a grey slab against this ground. Same treatment, so the two
   scroll areas match.
   ------------------------------------------------------------------- */
.js-inapp-stats-history{
  /* 580px, measured against the rendered right-hand column rather than
     calculated - the two columns then finish level, which is the whole
     point of capping it.

     A .gdp-session is 46px (10px padding top and bottom, 1px border each
     side, ~18px of line, 6px margin-bottom), so this is the sticky header
     plus about eleven sessions. More than the eight first asked for, but
     eight left the list visibly short beside the board. */
  max-height:580px;
  overflow-y:auto;
  padding-right:6px;
  scrollbar-width:thin;
  scrollbar-color:rgba(255,164,0,.45) transparent;
}
.js-inapp-stats-history::-webkit-scrollbar{width:8px;}
.js-inapp-stats-history::-webkit-scrollbar-track{background:transparent;}
.js-inapp-stats-history::-webkit-scrollbar-thumb{
  background:rgba(255,255,255,.16);border-radius:8px;
  border:2px solid transparent;background-clip:content-box;
}
.js-inapp-stats-history::-webkit-scrollbar-thumb:hover{
  background-color:rgba(255,164,0,.55);background-clip:content-box;
}

/* The column headings stay put while the rows move under them, otherwise
   scrolling two rows leaves seven unlabelled numbers. Background matches
   .gdp-stats-panel so rows do not show through. */
.js-inapp-stats-history .gdp-session.is-head{
  position:sticky;
  top:0;
  z-index:2;
  background:var(--gdp-bg);
}

@media(max-width:900px){
  /* Stacked: the list is above the board rather than beside it, and each
     row is taller because it has folded, so 580px would push the board off
     the screen on a phone. */
  .js-inapp-stats-history{max-height:52vh;}
}

/* =====================================================================
   The setup screen
   ---------------------------------------------------------------------
   The markup here is the game's original Bootstrap 3, and its class names
   carry JS behaviour, so this restyles in place rather than rewriting it
   to gdp- classes. Everything is scoped under .container-main-graphic,
   which raises specificity above the theme's plain .btn-start-game and
   .form-control and means other games are untouched even though those
   classes are shared.

   Colours and metrics are copied from the shared components they are
   standing in for, so the setup screen and the stats panel read as one
   design rather than two.
   ===================================================================== */

/* Primary action, in the palette's own --gdp-go rather than the accent.
   The system has a green kept specifically for start-and-go, which leaves
   the accent free for selection - and selection is what the accent means
   everywhere else here: the chosen target, the chosen chip, a Close dart. */
.container-main-graphic .btn-start-game{
  font-family:var(--gdp-font);
  font-size:16px;font-weight:600;
  background:var(--gdp-go);
  border:1px solid var(--gdp-go);
  color:var(--gdp-ink);
  border-radius:10px;
  padding:13px 28px;
}
.container-main-graphic .btn-start-game:hover{background:var(--gdp-go-hi);}

/* Secondary. Mirrors .gdp-btn - a quiet panel button, because sound is a
   preference and should not compete with Start Game. */
.container-main-graphic .btn-sound{
  font-family:var(--gdp-font);
  font-size:15px;
  background:var(--gdp-panel2);
  border:1px solid var(--gdp-line);
  color:var(--gdp-ink);
  border-radius:10px;
  padding:11px 20px;
}
.container-main-graphic .btn-sound:hover{border-color:#4a4a4a;}

/* Selects. Bootstrap's .form-control is white with a light border, which
   is the loudest thing on a dark screen. */
.container-main-graphic .setup-wrapper .form-control{
  font-family:var(--gdp-font);
  background:var(--gdp-panel2);
  border:1px solid var(--gdp-line);
  color:var(--gdp-ink);
  border-radius:8px;
  box-shadow:none;
  height:auto;
  padding:9px 12px;
}
.container-main-graphic .setup-wrapper .form-control:focus{
  border-color:var(--gdp-accent);
  box-shadow:none;
}

/* accent-color does the whole job on a checkbox in every current browser,
   and degrades to the platform default rather than to something broken. */
.container-main-graphic .setup-wrapper input[type="checkbox"]{
  accent-color:var(--gdp-accent);
  width:16px;height:16px;
  vertical-align:-2px;
}

/* The "Your stats" tab needs no styling here at all.

   The markup is -01's element - a button with gdp-statstab and the
   js-btn-app-stats trigger hook, nothing else - so the shared rule is the
   only one that matches and supplies the whole treatment: position, the
   -90deg rotation about its top-right corner, 13px Oswald in accent-ink on
   accent, the edge rounded only where it faces the game, the shadow, the
   brightness hover and the 700px adjustment.

   The previous version of this file fought the theme's .btn-app-stats with
   !important on every text property. Removing that class from the markup
   was the actual fix - the legacy rule cannot match what is not there.

   One thing is still needed: a containing block. gdp-statstab is
   position:absolute, and in -01 it sits inside .gdp-wrap, which is
   position:relative. */
.container-main-graphic{position:relative;}

/* Section labels. TARGET and LIMIT are labels, not headings, and at the
   shared .app-header-m size they compete with the game title. */
.container-main-graphic .setup-wrapper .app-header-m.uc{
  font-size:11px;
  letter-spacing:.18em;
  color:var(--gdp-muted);
}

/* =====================================================================
   In play
   ---------------------------------------------------------------------
   Nine dart buttons, a register button and an undo. Same approach as the
   setup screen: the classes carry JS behaviour, so only the look changes.

   The old scheme pre-coloured Miss dark red while Hit and Close sat navy,
   so a fresh throw looked as though Miss had already been chosen. All
   three now start identical and neutral, and colour only when picked -
   which is what the .hit-selected / .close-selected / .miss-selected
   classes already existed to express.

   Selected reads as a traffic light: green, amber, red. Register throw
   uses --gdp-go so the action a player presses forty times a session is
   never confused with the green that means a dart went in.
   ===================================================================== */

/* Nine buttons filled with solid colour is a lot of weight on one screen.
   The fills sit at 70% so the photograph reads through them and the board
   keeps some air, and the borders carry the colour at full strength - so
   the button is defined by its outline rather than by a slab.

   The rgba values are the palette tokens at .7. Written out rather than
   built with color-mix() because these are the most-pressed controls in
   the game and are not worth a browser-support question. If a token
   changes, change these:

     --gdp-win    #3ddc84   rgba(61,220,132,x)
     --gdp-accent #ffa400   rgba(255,164,0,x)
     --gdp-bust   #ff5a52   rgba(255,90,82,x)
     --gdp-go     #2c8a5a   rgba(44,138,90,x)
     --gdp-go-hi  #37a56d   rgba(55,165,109,x)
*/
.container-main-graphic .btn-game{
  font-family:var(--gdp-font);
  font-weight:400;
  letter-spacing:.04em;
  color:var(--gdp-ink);
  background-color:rgba(29,29,29,.7);
  /* Lighter than --gdp-line (#2b2b2b), which disappeared once the fills
     were translucent and there was less contrast holding the edge. */
  border:1px solid rgba(255,255,255,.18);
  border-radius:10px;
  opacity:1;
  transition:background-color .12s, border-color .12s, color .12s;
}
.container-main-graphic .btn-game:hover{
  opacity:1;
  border-color:rgba(255,255,255,.34);
}

.container-main-graphic .hit-selected{
  background-color:rgba(61,220,132,.7);
  border-color:var(--gdp-win);
  color:#06301c;
  font-weight:600;
}
.container-main-graphic .close-selected{
  background-color:rgba(255,164,0,.7);
  border-color:var(--gdp-accent);
  color:var(--gdp-accent-ink);
  font-weight:600;
}
/* White rather than the dark ink the other two use. Against the full
   strength red, #3a0d0a was fine; at 70% the fill blends to about #bb4842
   and that ink drops to a 3.3:1 contrast ratio, under the 4.5 threshold.
   White on the same blend is 5.1. */
.container-main-graphic .miss-selected,
.container-main-graphic .btn-bull-selected{
  background-color:rgba(255,90,82,.7);
  border-color:var(--gdp-bust);
  color:var(--gdp-ink);
  font-weight:600;
}

/* The keyboard shortcut in the corner of each button. Quiet - it is a hint,
   not part of the label. */
.container-main-graphic .btn-game .small-key{
  color:var(--gdp-muted);
  font-weight:400;
}
.container-main-graphic .hit-selected .small-key,
.container-main-graphic .close-selected .small-key,
.container-main-graphic .miss-selected .small-key{
  color:inherit;
  opacity:.55;
}

.container-main-graphic .register-button{
  background-color:rgba(44,138,90,.7);
  border-color:var(--gdp-go-hi);
  color:var(--gdp-ink);
  font-weight:600;
}
/* Hover firms up rather than changing hue - it is the same button, just
   about to be pressed. */
.container-main-graphic .register-button:hover{
  background-color:rgba(55,165,109,.85);
  border-color:var(--gdp-go-hi);
}

/* Undo is a way back, not a choice - a ghost button so it stays available
   without drawing the eye down from the dart buttons. */
.container-main-graphic .js-btn-undo-score{
  font-family:var(--gdp-font);
  font-size:13px;
  letter-spacing:.14em;
  background:transparent;
  border:1px solid var(--gdp-line);
  color:var(--gdp-muted);
  border-radius:9px;
  padding:8px 18px;
}
.container-main-graphic .js-btn-undo-score:hover{
  border-color:#4a4a4a;
  color:var(--gdp-ink);
}

/* The rules column and the setup labels sit directly on the photograph. At
   -01's tint strength there was enough black behind them; brightened, the
   thin Oswald weights start to lose their edges over the lit parts of the
   picture. Same fix -01 uses on .gdp-screen-setup .gdp-intro p - a shadow
   rather than a panel, so the photo still reads through. */
.container-main-graphic .js-title-instruction,
.container-main-graphic .setup-wrapper{
  text-shadow:0 1px 6px rgba(0,0,0,.75);
}

/* But not on the controls. text-shadow inherits, and these all sit on a
   solid ground of their own - black on amber when a target is selected,
   white on the go green, ink on a panel - where a shadow only softens
   edges that were already crisp. The shadow is for text that sits directly
   on the photograph. */
.container-main-graphic .btn-target-option,
.container-main-graphic .btn-start-game,
.container-main-graphic .btn-sound,
.container-main-graphic .form-control,
.container-main-graphic .btn-game,
.container-main-graphic .register-button,
.container-main-graphic .js-btn-undo-score{
  text-shadow:none;
}

/* The board box must stay SQUARE.

   The template sizes it width:500px height:500px max-width:100%, so on a
   narrow window the width shrinks and the height does not - a 360x500 box.
   The SVG inside is height:auto so it stays square at 360x360 at the top,
   while the canvas is inset:0 and stretches to 360x500. The hull and the
   darts are then stretched vertically and offset against the board, and a
   bull session starts looking like it was aimed at treble 3.

   aspect-ratio ties the height to the width instead, so both children get
   the same square box at any size. Higher specificity than the template's
   own rule and its mobile override, so it wins in both. */
.container-main-graphic .board-ingame-wrapper{
  /* Larger than the template's 500px - at that size the board sat in the
     middle of a lot of empty frame, and the whole point of this view is
     the board. Three caps, whichever bites first:

       680px  as much as the layout wants to give it
       66vh   so the square still fits the window vertically
       100%   so it never overflows a narrow one

     aspect-ratio ties the height to the width. The template sizes it
     500x500 with max-width:100%, so narrowing the window shrank the width
     and not the height - a 360x500 box, with the SVG square at 360 and the
     canvas stretched to 360x500. The hull and darts were then offset
     against the board, and a bull session looked aimed at treble 3. */
  width:min(680px, 66vh, 100%);
  max-width:100%;
  height:auto;
  aspect-ratio:1 / 1;
}

@media(max-width:767px){
  /* The template pulls this up 20px on a phone, which was tuned for the
     old fixed-height box and the label block that used to sit under the
     board. With the board sized off the viewport and the target label
     moved into the left column, it wants space above it instead. */
  .container-main-graphic .board-ingame-wrapper{
    margin-top:20px;
  }
}

/* =====================================================================
   The live board
   ---------------------------------------------------------------------
   The board is the shared SVG with the hit area on a canvas over it, both
   in the same +/-232mm frame, so scaling the wrapper scales all of it
   together and it stays sharp at any magnification. The old in-game view
   was a 500px bitmap, which is why this could not be done before.

   The viewport is circular. The board disc is round and its corners are
   transparent, so a square crop would show nothing there anyway - and
   once zoomed in, a circular window reads as looking through a lens
   rather than as a picture that has been cut off.
   ===================================================================== */
.gdp-zoom{
  position:absolute;
  inset:0;
  overflow:hidden;
  border-radius:50%;
  /* Feathered rather than a hard cut. A sharp circle reads as a shape
     stamped on the screen; a soft one reads as the edge of what can be
     seen, and lets the board dissolve into the photograph behind it.

     closest-side matters. Without it a radial-gradient sizes to
     farthest-corner, so 100% is the distance to the CORNER of the box -
     353px on a 500px square - and the whole fade lands outside the circle
     where nothing is drawn. The mask then does nothing and the hard edge
     from overflow:hidden is what shows.

     Opaque to 80% of the radius, then out across the last fifth. */
  -webkit-mask-image:radial-gradient(circle closest-side at 50% 50%,
    #000 0 80%, rgba(0,0,0,.72) 90%, rgba(0,0,0,.28) 97%, transparent 100%);
  mask-image:radial-gradient(circle closest-side at 50% 50%,
    #000 0 80%, rgba(0,0,0,.72) 90%, rgba(0,0,0,.28) 97%, transparent 100%);
}
.gdp-zoom-inner{
  position:absolute;
  inset:0;
  transform-origin:50% 50%;
  /* Slow and heavily eased, with a touch of overshoot so it settles into
     place rather than arriving flat. This moves while a player is at the
     oche, so it should read as the view finding focus, not as a jump. */
  transition:transform 1000ms cubic-bezier(.22,1.12,.32,1);
  will-change:transform;
}

/* No blur while travelling. It was meant to read as a camera refocusing,
   but a blurred board just reads as a low resolution board - the effect
   and the failure look identical, so the effect loses. The ring pulse on
   landing stays: that one happens when the board is already sharp. */

/* One pulse where the view lands, so the arrival is punctuated rather than
   just stopping. Sits above the board and takes no clicks. */
.gdp-zoom-flash{
  position:absolute;
  left:50%;
  top:50%;
  width:36%;
  height:36%;
  margin:-18% 0 0 -18%;
  border-radius:50%;
  border:2px solid rgba(255,164,0,.85);
  opacity:0;
  pointer-events:none;
  z-index:3;
}
.gdp-zoom-flash.is-on{
  animation:gdpZoomPulse 780ms cubic-bezier(.16,1,.3,1) 1;
}
@keyframes gdpZoomPulse{
  0%   { opacity:0;   transform:scale(.35); }
  35%  { opacity:.95; }
  100% { opacity:0;   transform:scale(1.5); }
}

@media(prefers-reduced-motion:reduce){
  .gdp-zoom-flash.is-on{animation:none;}
}
.gdp-zoom-inner .gdp-board{display:block;width:100%;height:auto;}
.gdp-zoom-inner canvas{position:absolute;inset:0;width:100%;height:100%;}

@media(prefers-reduced-motion:reduce){
  .gdp-zoom-inner{transition:none;}
}

/* =====================================================================
   In-game labels
   ---------------------------------------------------------------------
   One pattern, used everywhere: a small uppercase label with wide
   tracking, the value under it. The screen previously carried four
   patterns for the same idea - "HITS: 2" inline with a colon, "HIT AREA"
   stacked, "YOUR DEDICATION" stacked at another size, "Darts tracked: 3"
   as a sentence - which read as four separate decisions rather than one
   thing repeated.

   Hierarchy: hits is the score and wins. Darts and hit area are context
   and sit at half its size. The game title drops to a tag.
   ===================================================================== */

.gdp-figrow{
  display:flex;
  gap:30px;
  justify-content:flex-end;
  align-items:flex-end;
}

.gdp-fig{
  display:flex;
  flex-direction:column;
  align-items:flex-end;
  line-height:1;
}
.gdp-fig.is-left{align-items:flex-start;}

.gdp-fig-l{
  font-family:var(--gdp-font);
  font-size:11px;
  font-weight:400;
  letter-spacing:.2em;
  text-transform:uppercase;
  color:rgba(255,255,255,.45);
  margin-bottom:4px;
}
/* The target label is accent because the crosshair on the board is too -
   the word and the mark are naming the same thing. */
.gdp-fig-l.is-accent{color:var(--gdp-accent);}

.gdp-fig-v{
  font-family:var(--gdp-font);
  font-weight:400;
  /* Without this a 2 and a 3 are different widths and the whole row shifts
     every time the score changes. */
  font-variant-numeric:tabular-nums;
  line-height:.92;
}
.gdp-fig-v.is-primary{font-size:clamp(34px,6vw,52px);}
.gdp-fig-v.is-sub{
  font-size:clamp(22px,3.4vw,30px);
  font-weight:300;
  color:rgba(255,255,255,.78);
}
.gdp-fig-v.is-target{
  font-size:clamp(28px,4.6vw,40px);
  font-weight:300;
  text-transform:uppercase;
}

/* The unit rides beside the figure rather than competing with it.

   Unscoped on purpose. This was written under .gdp-fig-v, the in-game
   figures, so the same span inside a .gdp-figure card on the stats panel
   got no styling at all: full size, and long enough to wrap the unit onto
   its own line under the number. Same markup in both places, so the rule
   belongs to the span rather than to either container. */
.gdp-unit{
  font-size:.5em;
  font-weight:400;
  color:rgba(255,255,255,.55);
  margin-left:2px;
  white-space:nowrap;
}

/* And the value itself never breaks between the number and its unit. */
.gdp-fig-v,
.gdp-figure b{
  white-space:nowrap;
}

/* Inside a figure card the unit needs more than .gdp-unit can give it.
   gdp-game.css styles EVERY span in a card as the label underneath:

     .gdp-figure span{display:block;font-size:10px;letter-spacing:.16em;
                      text-transform:uppercase;margin-top:6px;}

   which is (0,1,1) against .gdp-unit's (0,1,0) - so the unit was being
   turned into a block and dropped onto its own line, wearing the label's
   size and tracking. Everything that rule sets has to be undone here.

   Not fixed in the shared file: .gdp-figure span meaning "the label" is
   right for every game that has one span in a card. This one has two. */
.gdp-figure .gdp-unit{
  display:inline;
  font-size:.5em;
  font-weight:400;
  letter-spacing:normal;
  text-transform:none;
  color:rgba(255,255,255,.55);
  margin-top:0;
  margin-left:2px;
}

.gdp-game-tag{
  font-family:var(--gdp-font);
  font-size:12px;
  font-weight:400;
  letter-spacing:.22em;
  color:rgba(255,255,255,.42);
}

/* Status lines. Were green - the only green on the screen besides Register
   Throw, and sentence case among all caps, so they read as the system
   muttering to itself. Waiting is quiet; an instruction is accent, with a
   dot, so it looks like the game asking for something. */
.gdp-status{
  font-family:var(--gdp-font);
  font-size:13px;
  letter-spacing:.16em;
  text-transform:uppercase;
  color:rgba(255,255,255,.55);
}
.gdp-status.is-action{
  color:var(--gdp-accent);
  display:flex;
  align-items:center;
  gap:9px;
}
.gdp-status.is-action:before{
  content:"";
  width:7px;height:7px;
  border-radius:50%;
  background:var(--gdp-accent);
  flex:0 0 auto;
}

/* The way out of the hit-area view when tracking goes wrong. Quiet: it is
   a recovery control, not part of playing. Centred under the board it was
   the single most prominent thing on the screen. */
.gdp-escape{
  font-family:var(--gdp-font);
  font-size:11px;
  letter-spacing:.18em;
  color:rgba(255,255,255,.42);
  cursor:pointer;
  /* The game tag above it is hidden, so this now sits directly under the
     sound and delete icons and needs its own clearance rather than just
     the gap after the tag. */
  margin-top:14px;
  transition:color .15s;
}
.gdp-escape:hover{color:var(--gdp-accent);}
.gdp-escape.hidden{display:none;}

/* The "Your stats" tab sits at top:170px on a desktop, dropping to 120px
   below 700px in the shared rule. Neither clears Dedication's options once
   the layout stacks: the setup column is col-md-5, so from 991px down it
   goes full width and runs straight under the tab.

   991px rather than a phone breakpoint for that reason - the collision
   starts wherever the columns stack, not at any particular device. Narrow
   it to 767px if tablets turn out to have room.

   Scoped under .container-main-graphic so it beats the shared 700px rule
   at every width, rather than only where the two happen to overlap. */
@media(max-width:991px){
  .container-main-graphic .gdp-statstab{
    top:70px;
  }
}

/* The demo badge, centred on the board.

   In the corner it was easy to miss, and a label a player misses on a set
   of numbers that are not theirs is the one label that has to land. In the
   middle it sits over the bull, where the demo group is thinnest - the
   darts are up at the treble 20 - so it covers the picture it is
   annotating least.

   Outline rather than a solid chip: legible without becoming the brightest
   thing on a board it is only labelling. */
.gdp-demo-badge{
  position:absolute;
  top:50%;
  left:50%;
  transform:translate(-50%,-50%);
  z-index:4;
  font-family:var(--gdp-font);
  font-size:10px;
  letter-spacing:.2em;
  text-transform:uppercase;
  color:var(--gdp-accent);
  background:rgba(10,10,10,.72);
  border:1px solid rgba(255,164,0,.55);
  border-radius:20px;
  padding:4px 11px;
  pointer-events:none;
}

/* Best area with no board registered. The value slot carries the reason
   rather than a dash, so it needs to be text-sized and to sit on the same
   baseline as the numbers beside it. */
.gdp-figure.is-best.is-locked b{
  font-size:13px;
  font-weight:400;
  letter-spacing:.06em;
  color:var(--gdp-accent);
  line-height:1.9;
}
.gdp-figure.is-best.is-locked b a{
  color:inherit;
  border-bottom:1px solid rgba(255,164,0,.45);
  text-decoration:none;
}
.gdp-figure.is-best.is-locked b a:hover{border-bottom-color:var(--gdp-accent);}

/* Dart filter for the heat map. Smaller than the mode chips above it: it
   is a subdivision of the heat map, not a peer of it. */
.gdp-dart-filters{
  justify-content:center;
  margin:10px 0 2px;
}
.gdp-dart-filters .gdp-chip{
  font-size:11.5px;
  padding:6px 10px;
  letter-spacing:.04em;
}

/* The reset pulse. ALL is selected for the player whenever they change
   session or target, and a control that changes on its own should be seen
   changing - otherwise they wonder why the map moved. */
.gdp-chip.is-reset{
  animation:gdpChipReset 620ms cubic-bezier(.16,1,.3,1) 1;
}
@keyframes gdpChipReset{
  0%   { box-shadow:0 0 0 0 rgba(255,164,0,.55); }
  55%  { box-shadow:0 0 0 7px rgba(255,164,0,0); }
  100% { box-shadow:0 0 0 0 rgba(255,164,0,0); }
}
@media(prefers-reduced-motion:reduce){
  .gdp-chip.is-reset{animation:none;}
}
